This is a migrated thread and some comments may be shown as answers.

Multiple files for MappingConfiguration for each entity

4 Answers 61 Views
Data Access Free Edition
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Gary
Top achievements
Rank 1
Gary asked on 27 Aug 2015, 02:13 PM

I am trying to clean up my code a bit and attempted to break out the mapping code for each entity into it's own file, accessible via a static method Map(). These are all in the same assembly, project, namespace, and even folder. I am however, running into some issues ... 

Here's an example of one on my mapping classes ... 

 

public class ModelBaseMap
{
    public static MappingConfiguration<ModelBase> Map()
    {
        //
        // We need to map the ModelBase as well using Horizontal Inheritance
        MappingConfiguration<ModelBase> map = new MappingConfiguration<ModelBase>();
        map.MapType().Inheritance(Telerik.OpenAccess.InheritanceStrategy.Horizontal);
 
        return map;
    }
}

 And here is the metadatsource file ... 

 

public partial class DbContextMetadataSource : FluentMetadataSource
{
    protected override IList<MappingConfiguration> PrepareMapping()
    {
        List<MappingConfiguration> configurations = new List<MappingConfiguration>();
 
        MappingConfiguration<ModelBase> modelBaseMap         = ModelBaseMap.Map();           
        MappingConfiguration<DeliverableType> typeMap        = DeliverableTypeMap.Map();
        MappingConfiguration<Deliverable> delMap             = DeliverableMap.Map();
        MappingConfiguration<DeliverablePackage> pkgMap      = DeliverablePackageMap.Map();
        MappingConfiguration<DeliverablePackageItem> itemMap = DeliverablePackageItemMap.Map();
         
        configurations.Add(modelBaseMap);
        configurations.Add(typeMap);
        configurations.Add(delMap);
        configurations.Add(pkgMap);
        configurations.Add(itemMap);
 
        return configurations;
    }
}

 I am getting the following error ... 

 

Telerik.OpenAccess.Exceptions.ConfigurationException: Found configurations for property 'CreatedDate' of class 'InnovativeFoto.BLL.Models.ModelBase' both in the PrepareMapping method of the FluentMetadataContext and in the class static method returning MappingConfiguration

 

 Is this not allowed? MUST the mapping all exist in the actual MetaDataSource file?

 

 

 

 

 

4 Answers, 1 is accepted

Sort by
0
Accepted
George
Top achievements
Rank 1
answered on 27 Aug 2015, 02:30 PM

 I did this in my company's code base so it can be done.

The problem is, There is a class scanner that looks for Public Static methods that return a MappingConfiguration<T>.  This means both the ModelBaseMap and the DbContextMetadataSource methods get called, and you get an 'already mapped' style exception.

You can either remove the call to the static method in DbContextMetadataSource  and let the scanner pick up the mapping methods from the other classes or make the ModelBaseMap.Map() methods non-static.  In my case, I went with removing the mapping code from the MetaDataSource and let that define the global properties of the container, and pushed the map methods out to the other classes.

 

public class MappedClass
{
  //Properties stuff {get; set;}
 
  [SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "Called by the reflection from Data Access.")]
  public static MappingConfiguration<MappedClass> GetMappedClassMappingConfiguration()
  {
    MappingConfiguration<MappedClass> configuration = GetMappedClassClassConfiguration();
    PrepareMappedClassPropertyConfigurations(configuration);
 
    return configuration;
  }
 
  private static MappingConfiguration<MappedClass> GetMappedClassClassConfiguration()
  {
    MappingConfiguration<MappedClass> configuration = new MappingConfiguration<MappedClass>();
    configuration.MapType(x => new {})
      .WithConcurencyControl(OptimisticConcurrencyControlStrategy.Changed)
      .ToTable("db_table");
 
    return configuration;
  }
 
  private static void PrepareMappedClassPropertyConfigurations(MappingConfiguration<MappedClass> configuration)
  {
    //Map the properties.
  }
}

 

#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the FluentMappingGenerator.ttinclude code generation file.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using Telerik.OpenAccess.Metadata;
using Telerik.OpenAccess.Metadata.Fluent;
 
namespace Entities.BaseModel
{
  public partial class FluentModelMetadataSource : FluentMetadataSource
  {
    protected override IList<MappingConfiguration> PrepareMapping()
    {
      List<MappingConfiguration> mappingConfigurations = new List<MappingConfiguration>();
 
      return mappingConfigurations;
    }
 
    protected override void SetContainerSettings(MetadataContainer container)
    {
      container.Name = "FluentModel";
      container.DefaultNamespace = "Entities";
      container.NameGenerator.SourceStrategy = Telerik.OpenAccess.Metadata.NamingSourceStrategy.AutoProperty;
      container.NameGenerator.RemoveCamelCase = false;
    }
  }
}
 
#pragma warning restore 1591

 

 

 

0
Gary
Top achievements
Rank 1
answered on 27 Aug 2015, 03:21 PM

Thank you for such a quick response!! Your reply absolutely answered my question (Thank you) but raised a couple of questions/thoughts ... 

  • I noticed, in your example, that there was no longer an explicit call to "configurations.add(map)" in the ​MetadData​Source​; which makes sense since ​it no longer contains references to the MappingConfigurations. I assume then, that the class scanner knows to add the MappingConfgurations from the public static calls to the List<MappingConfiguration> collection?
  • I may want to support multiple contexts, thusly would require multiple MetaDataSources (one for each context). If I understand correctly if use instance methods instead of public static methods ... would this be do-able? (Code example below )

 

public partial class DbContextMetadataSource : FluentMetadataSource
{
    protected override IList<MappingConfiguration> PrepareMapping()
    {
        List<MappingConfiguration> configurations = new List<MappingConfiguration>();
  
        ModelBaseMap baseMapper                              = new ModelBaseMap();
        MappingConfiguration<ModelBase> modelBaseMap         = baseMapper.Map();
         
        DeliverableTypeMap typeMapper                        = new DeliverableTypeMap();
        MappingConfiguration<DeliverableType> typeMap        = typeMapper.Map();
         
        DeliverableMap deliverableMapper                     = new DeliverableMap();
        MappingConfiguration<Deliverable> delMap             = deliverableMapper.Map();
         
        DeliverablePackageMap packageMapper                  = new DeliverablePackageMap();
        MappingConfiguration<DeliverablePackage> pkgMap      = packageMapper.Map();
         
        DeliverablePackageItemMap itemMapper                 = new DeliverablePackageItemMap();
        MappingConfiguration<DeliverablePackageItem> itemMap = itemMapper.Map();
          
        configurations.Add(modelBaseMap);
        configurations.Add(typeMap);
        configurations.Add(delMap);
        configurations.Add(pkgMap);
        configurations.Add(itemMap);
  
        return configurations;
    }
}
 
public partial class AnotherDbContextMetadataSource : FluentMetadataSource
{
    protected override IList<MappingConfiguration> PrepareMapping()
    {
        List<MappingConfiguration> configurations = new List<MappingConfiguration>();
  
        ModelBaseMap baseMapper                      = new ModelBaseMap();
        MappingConfiguration<ModelBase> modelBaseMap = baseMapper.Map();
         
        AccountMap acctMapper                        = new AccountMap();
        MappingConfiguration<Account> typeMap        = acctMapper.Map();
         
        AccountTypeMap typeMapper                    = new AccountTypeMap();
        MappingConfiguration<AccountType> acctMap    = typeMapper.Map();
          
        configurations.Add(modelBaseMap);
        configurations.Add(typeMap);
        configurations.Add(acctMap);
  
        return configurations;
    }
}
 
 
 
public partial class DbContext : OpenAccessContext
{
    // ... Entity defintions here
     
 
    private static string connectionStringName = @"Connection";
 
    private static BackendConfiguration backend = GetBackendConfiguration();
 
    private static MetadataSource metadataSource = new DbContextMetadataSource();
 
    public DbContext() : base(connectionStringName, backend, metadataSource) {}
 
    public static BackendConfiguration GetBackendConfiguration()
    {
        BackendConfiguration backend = new BackendConfiguration();
        backend.Backend              = "MsSql";
        backend.ProviderName         = "System.Data.SqlClient";
 
        return backend;
    }
}
 
 
 
public partial class AnotherDbContext : OpenAccessContext
{
    // ... Entity defintions here
     
 
    private static string connectionStringName = @"Connection";
 
    private static BackendConfiguration backend = GetBackendConfiguration();
 
    private static MetadataSource metadataSource = new AnotherDbContextMetadataSource();
 
    public DbContext() : base(connectionStringName, backend, metadataSource) {}
 
    public static BackendConfiguration GetBackendConfiguration()
    {
        BackendConfiguration backend = new BackendConfiguration();
        backend.Backend              = "MsSql";
        backend.ProviderName         = "System.Data.SqlClient";
 
        return backend;
    }
}

 

0
George
Top achievements
Rank 1
answered on 27 Aug 2015, 03:58 PM

[quote]gstenstrom said:

I noticed, in your example, that there was no longer an explicit call to "configurations.add(map)" in the ​MetadData​Source​; which makes sense since ​it no longer contains references to the MappingConfigurations. I assume then, that the class scanner knows to add the MappingConfgurations from the public static calls to the List<MappingConfiguration> collection?

[/quote]

 Correct.   I do not remember having to play around to get the mappings to be picked up.

[quote]gstenstrom said:​

I may want to support multiple contexts, thusly would require multiple MetaDataSources (one for each context). If I understand correctly if use instance methods instead of public static methods ... would this be do-able? (Code example below )
[/quote]

 I have not  played around with this case, so you may need to wait for a official Telirik answer on this one.  I do have multiple contexts, but I keep them in different projects/namespaces and they do not interact with each other.  I do know that I ran into Default Namespace exceptions and Aggregate metadata exceptions when I had them mis-configured.  I do know that data access supports multiple contexts and merging metadata though.   They describe such operations in their docs:  http://docs.telerik.com/data-access/developers-guide/data-access-model/advanced-model-tasks/multiple-models/devguide-data-access-advanced-tasks-multiple-models-overview

0
Accepted
Kaloyan Nikolov
Telerik team
answered on 28 Aug 2015, 11:04 AM
Hi,

The static methods providing the mapping configuration inside a the entity classes are discovered at run-time and are best to use in case of single Context/MetadataSource.

If you plan to have multiple I would suggest you to go in more explicit way and use either the approach with the instance methods discussed below  (where the disadvantage is that you should instantiate the entity once) or you could use static methods with a bit different signature so that they not discovered automatically. It could be something like this:
//In your entity classes
public static void ConfigureMapping(IList<MappingConfiguration> configuration)
{
    var productsMap = ...
     
    configuration.Add(productsMap);
}
 
//then in your MetadataSource your code would be:
protected override IList<MappingConfiguration> PrepareMapping()
{
    List<MappingConfiguration> configurations = new List<MappingConfiguration>();
 
    Product.ConfigureMapping(configurations);
 
    return configurations;
}

I hope this helps. 

Regards,
Kaloyan Nikolov
Telerik
 
Check out the latest announcement about Telerik Data Access vNext as a powerful framework able to solve core development problems.
Tags
Data Access Free Edition
Asked by
Gary
Top achievements
Rank 1
Answers by
George
Top achievements
Rank 1
Gary
Top achievements
Rank 1
Kaloyan Nikolov
Telerik team
Share this question
or