Entity Framework Many to Many Relationship

The theory for many to many relationship is simple: you map two entities with key that you define on each side and Entity Framework generate the table that you have assigned the name with. Something like the code below works perfectly. The problem occurs when you want to save entities later.

this.HasMany(d => d.Moderators).WithMany(d => d.ContestsUserModerate).Map(ul=> {
                ul.MapRightKey("ApplicationUserModeratorId");
                ul.MapLeftKey("ContestId");
                ul.ToTable("ContestModerators", Constants.SchemaNames.User);
            });

The problem is is you save the entity on which you configured the many to many relationship than you might get problem with Entity Framework trying to insert the two entities you are trying to maps. The problem is that if you have entity A that try to have B than A.B is having the entity and not a foreign key attribute. The same is true for B.A which is having a collection of A. In both case, it’s a collection of entities. The problem is bigger than just trying to insert those entity cause you could just write in your save method a code to mark those collection’s entities the status to UnChanged. But, the problem is that if you have rich entities than this one will contains other entities. So you have to go through all of its entities and handle all states of each properties or nullify all properties and use the foreign key properties. This is simply not viable for big classes.

The solution is to forget about the Map method of Entity Framework and to create your own association entity.

For example, the previous code we were having an Entity called Contest that try to get a many to many to ApplicationUser. So, you create a ContestApplicationUser class. Than, you have in both entities (Contest and ApplicationUser) a collection of the new class you just created : ContestApplicationUser. You need to create a configuration for ContestApplicationUser which will define the primary key which should be the primary key of both entities. This can be done by specifying in an anonymous class both primary key of your classes. Finally, you need to specify that both properties are required in the class and that this one has a relationship to the specific entity they both represent.

public class ContestApplicationUserConfiguration : AssociationConfiguration<ContestApplicationUser>
{
    public ContestApplicationUserConfiguration() : base(Constants.SchemaNames.Contest)
    {
        this.HasKey(c => new { UserId = c.UserId, ContestId = c.ContestId });
        this.HasRequired(d => d.Contest).WithMany(d => d.Users).HasForeignKey(d => d.ContestId);
        this.HasRequired(d => d.User).WithMany(d => d.Contests).HasForeignKey(d => d.UserId);
    }
}

The AssociationConfiguration class is a class I created that simply an helper that create the table name with the type of the entity.

 public abstract class AssociationConfiguration<T> : EntityTypeConfiguration<T> where T : class
    {
        protected AssociationConfiguration(string schemaName)
        {
            ToTable(typeof(T).Name, schemaName);
        }
    }

From here, it’s very simple to save any new associations. You just need to instantiate the class, ContestApplicationUser and you just fill up the two properties for the foreign keys. On the other way around, when you load the entities with the collection you will include the collection and the other side.

    .Include(d => d.Users)
    .Include(d => d.Users.Select(f=>f.User))

No more hassle when saving and still the full ledge entity when loading. One caveat of this solution is that you cannot insert new association before having both of the entity already inserted.

Redis’ Service Eating Windows Hard drive Space

I noticed my hard drive losing space faster than usually. I decided to run a tool named “WinDirStat” which is free and allow to get a portrait of your hard drive. Within few seconds, the culprit was inside Windows folder, to be more accurate: C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Redis.

RedisServerWindowsSpaceHarddrive

I am running Redis as a service on my machine since about 2 months and never realized that this one store the size of the ram of your machine in multiple files. Each files are named with “RedisQFork_9076.dat” and the number vary. Each of them were 8 gigs because I had a 8 gig ram machine.

This only occur on 64bits OS, otherwise it is cap limited to 500 megs. So why does these files are created? Because Redis was created to be on Linux first. The Windows version needs to mimic some behaviors. Redis clusters, backup, synchronization needs to use the fork command that Windows OS does not have. So, it uses the file system.

To clean up, you need to go to C:\Windows\ServiceProfiles\NetworkService\AppData\Local\Redis but before deleting anything, you must stop the Windows service named “Redis”. Then, you can delete all files from that folder and start again the service.

If you want to move these files into another directory, this is possible with the latest Windows Redis version. Go in the configuration file of Redis located:
C:\Program Files\Redis\redis.windows-service.conf. Search for heapdir. It’s also possible to limit the size by changing the setting named maxheap.

How to share app.config or web.config to many projects

Instead of duplicating the same information over and over again in multiple projects you should use the same file. A typical scenario can be that you have 1 console project for each web job and you want them to have the same app.config that share the same AppSetting configurations and the same Connection Strings.

The trick is to have in a central place the app.config file and to add a existing item as a link instead of a link. This hidden feature combined with some file property allow you to have the single instance of AppSetting on every bin folder.

The first step, is to select the project where you want to use the shared file. There is some ways to do it. The simplest is to right click the project, select Add and Existing Item.
AddExistingItem

The second step was unknown by me for many years. It’s very hidden. In the Add Existing Item, the dialog allows you to select any type of file. Watch out for the file extension filter. Below the file extension drop down, you have a button which by default is set to Add. Once you have selected the AppSetting file, instead of clicking on Add, go in the dropdown and select Add as Link. This is an awkward experience because you must select the file first because this dropdown on value change trigger the action.

AddAsLink

The last step is to go into the property of the link and to change the compilation behavior. The desired state is to have the app.config in your bin folder. Thus, you must change the file property to set the Build Action to Content and the Copy to output to Copy if newer (or always).

To wrap up, we have now in the solution explorer one file, or many depending of how many links you have setup. These links are not duplicated file, so if you are linking them from several projects editing anyone of the link will edit values for every one. This is very powerful and allows you to not repeat yourself. If you want to be sure that you have really added the file as a link, just check the solution explorer for the blue icon.
appSettingLinksInSolutionExplorer

How to copy attribute from one property to another

Earlier, I showed how to transfer attribute form model class to view model class with AutoMapper and Asp.Net MVC. This work fine but what if the view model class has a custom property that manipulate even further the data and that you would like to display on screen a display attribute from another property of the model class? The solution we had in the previous post transferred the display attribute from the model to the view model’s property by using AutoMapper to map the DisplayAttribute with the corresponding From and To property. But how can we extends this logic to be able to pass this attribute to another property of the view model class? This is what we will resolve in this article. The following image illustratre the desired result. We want the property B from the view model to use the p roperty A display attribute that come from the model property A.
ModelToViewModel

The first part, is already been done in the AutoMap code from the previous article. This is the code that map the attribute from the model to view model. The next step is to specify in the view model that we need to transfer from one property’s attribute to the other property. This require to create a new attribute where we can specify from which property we want to get the attributes.

public class CopyAttributesFrom : Attribute
{
    public string PropertyName { get; set; }
}

Then, we need to use it in the view model class. This class is limited to one property: the name of the property to take attributes. The mapping is than 1-1, nothing fancy. Let’s see an example. The following code is having two property. The first one get from the model some attributes and the second one want to get the attribute from the first property (which also has once mapped the ones from the model).

public TimeSpan? MinimumHoldingTime { get; set; }

[CopyAttributesFrom(PropertyName = "MinimumHoldingTime")]
public int? MinimumHoldingTimeMinutes {
    get { 
        return  this.MinimumHoldingTime.HasValue ? Convert.ToInt32(this.MinimumHoldingTime.Value.TotalMinutes) : (int?)null;
    }
}

Why don’t we map directly into AutoMapper the logic? Because the code we are using to transfer attributes from the model to viewmodel works with DestinationProperty and not an expression. Having logic in the ForMember method of AutoMapper uses an expression. This force us to map the value and in a second step to have the property desired with the data manipulated.

In the code to map with AutoMapper model attributes to view model, we had a custom DataAnnotationsModelMetadataProvider. This one need to be adjusted to add attributes from our custom a CopyAttributesFrom attribute.

public class MappedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private readonly IConfigurationProvider mapper;

    public MappedDataAnnotationsModelMetadataProvider(IConfigurationProvider mapper)
    {
        this.mapper = mapper;
    }

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        //Copy attributes from the model and to the view model
        var mappedAttributes = containerType == null ? attributes.ToList() : mapper.GetMappedAttributes(containerType, propertyName, attributes).ToList();

        //Map CopyAttributes attributes
        foreach (var attributeCopy in attributes.Where(d => d.GetType() == typeof (CopyAttributesFrom)).Cast<CopyAttributesFrom>())
        {
            var propertyFromTheMappedModelOfTheCopiedProperty = mapper.GetMappedAttributes(containerType, attributeCopy.PropertyName, attributes).ToList();
            mappedAttributes.AddRange(propertyFromTheMappedModelOfTheCopiedProperty);
        }
        var modelMetadata = base.CreateMetadata(mappedAttributes, containerType, modelAccessor, modelType, propertyName);
        return modelMetadata;
    }
}

The foreach is where everything happen. We verify that the property we map is marked with our copy attribute; if yes, we go in AutoMapper to get from the model the attributes. We must go back to the model and not directly copy the attributes from the specified viewmodel’s attribute because this one may not already been transferred from the model — we do not control the order that CreateMetaData is invoked. Nevertheless, this is not a problem, we take the view model property name, and instead of binding the attribute to the property specified we bind them to the property we are creating the metadata.

If you are not using this whole AutoMapper model/view model mapping, you can get a similar result by using the .Net framework. Here is how.

var sourceProperty = containerType.GetProperty(attributeCopy.PropertyName);
var allAttributeFromSpecifiedProperty = sourceProperty.GetCustomAttributes(true);
foreach (object attr in allAttributeFromSpecifiedProperty)
{
    mappedAttributes.Add(attr as Attribute);
}

Nonetheless, this solution has a pitfall which is the way we specify the property to copy the attributes — this one is hardcoded. Refactoring of this class is harder and the string may be unsynchronize with a property rename. However, since we localize the copy to the class itself and not beyond this boundary, the instability is restrained. This is a limitation of the actual .Net framework which does not allow to use expression inside an attribute.