I am trying to do something like this:
AutoMapper.Mapper.CreateMap<UrlPickerState, Link>()
.ForMember(m=>m.OpenInNewWindow,map=>map.MapFrom(s=>s.NewWindow))
.AfterMap((picker, link) => link = !string.IsNullOrWhiteSpace(link.Url)?link:null) ;
var pickerState = new UrlPickerState();
var linkOutput = AutoMapper.Mapper.Map<Link>(pickerState);
However, the assigned value of link is not used in any execution path.
I would like linkOutput to be null, but it is not.
How would I make the destination object null?
Details of objects involved:
public class Link
{
public string Title { get; set; }
public string Url { get; set; }
public bool OpenInNewWindow { get; set; }
}
public class UrlPickerState
{
public string Title { get; set; }
public string Url { get; set; }
public bool NewWindow { get; set; }
//.... etc
}
Here's a fiddle: http://dotnetfiddle.net/hy2nIa
This is the solution I used in the end, it was a bit more manual internally, but does not require any extra plumbing.
If anyone has a more elegant solution, it would be appreciated.
config.CreateMap<UrlPickerState, Link>()
.ConvertUsing(arg =>
{
if (string.IsNullOrWhiteSpace(arg.Url))
{
return null;
}
return new Link()
{
Url = arg.Url,
OpenInNewWindow = arg.NewWindow,
Title = arg.Title,
};
});
I created the following extension method to solve this problem.
public static IMappingExpression<TSource, TDestination> PreCondition<TSource, TDestination>(
this IMappingExpression<TSource, TDestination> mapping
, Func<TSource, bool> condition
)
where TDestination : new()
{
// This will configure the mapping to return null if the source object condition fails
mapping.ConstructUsing(
src => condition(src)
? new TDestination()
: default(TDestination)
);
// This will configure the mapping to ignore all member mappings to the null destination object
mapping.ForAllMembers(opt => opt.PreCondition(condition));
return mapping;
}
For the case in question, it can be used like this:
Mapper.CreateMap<UrlPickerState, Link>()
.ForMember(dest => dest.OpenInNewWindow, opt => opt.MapFrom(src => src.NewWindow))
.PreCondition(src => !string.IsNullOrWhiteSpace(src.Url));
Now, if the condition fails, the mapper will return null; otherwise, it will return the mapped object.
I think that will have to be done outside the mapping. Since AutoMapper requires an instance to map to, setting the destination to null seems like it should go outside the mapping.
I would instead do something like:
AutoMapper.Mapper.CreateMap<UrlPickerState, Link>()
.ForMember(m=>m.OpenInNewWindow,map=>map.MapFrom(s=>s.NewWindow));
var pickerState = new UrlPickerState();
Link linkOutput = null;
if(!string.IsNullOrWhiteSpace(pickerState.Url)) // or whatever condition is appropriate
linkOutput = AutoMapper.Mapper.Map<Link>(pickerState);
Related
I have some code I am trying to convert. I don't have these ObjectResult and ObjectContext anymore
This is what I did have:
public virtual ObjectResult<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new ObjectParameter("IN_MEM_ID", iN_MEM_ID) :
new ObjectParameter("IN_MEM_ID", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("GetTransData", iN_MEM_IDParameter);
}
Since I need a List to be returned from a caller ( it is sent back as json data )
This is what I am trying to build
public virtual List<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new SqlParameter("IN_MEM_ID", iN_MEM_ID) :
new SqlParameter("IN_MEM_ID", typeof(string));
Clinical_CaseTrakker_Context clinical = new Clinical_CaseTrakker_Context();
List<string> offLine = clinical.string.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter);
return offLine;
}
Notice that I am stuck with clinical.string i can't do that , but I am not sure how to take dbcontext instance and run FromSql to execute sql and return to List
In EF Core, it is not possible to use the FromSql method to return a subset of properties (a projection) directly from the database.
You are required to define a some model and a DbSet for that class
public class Foo
{
public string Bar { get; set; }
}
then declare in your context
public DbSet<Foo> Foos { get; set; }
and use it like:
using (var context = new Clinical_CaseTrakker_Context())
{
var offLine = context.Foos
.FromSql($"EXECUTE CT.GetTransData {iN_MEM_IDParameter}")
.Select(x => x.Bar)
.ToList();
return offLine;
}
Your Context needs a virtual DbSet<string> ResultStrings { get; set; } that you can call upon and put the result in. (This does not work, see this post or Roman Marusyk comment below)
EDIT: Your Context needs a virtual DbSet<ResultEntity> ResultEntities { get; set; } that you can call upon and put the result in.
Then you can do return clinical.ResultEntities.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter").toList() to fill the set.
Considering the ResultEntity has an Id and a value property, you can do ResultEntities.Select(e => e.value).toList() to extract a list of strings from the set.
I am trying to configure AutoMapper to work with a class which requires a constructor argument. I've done quite a bit of online research into this, and found several examples...but they either don't use instance-based AutoMapper, or they are for older versions of AutoMapper.
I'm using AutoMapper to deep clone objects. Here's the profile I've created:
public class ScannerAutoMapProfile : Profile
{
public ScannerAutoMapProfile()
{
CreateMap<AzureConfiguration>();
CreateMap<CommunityUser>();
CreateMap<Community>();
CreateMap<Contact>();
CreateMap<DatabaseConnection>();
CreateMap<DatabaseConfiguration>();
CreateMap<LoginManagement>();
CreateMap<MaxLoadSeconds>();
CreateMap<ScanTime>();
CreateMap<ScanningAcceleration>();
CreateMap<ScanningWindow>();
CreateMap<ScanningInterval>();
CreateMap<Scanning>();
CreateMap<SearchParameterUser>();
CreateMap<SearchParameter>();
CreateMap<ScannerConfiguration>();
}
private void CreateMap<TModel>()
{
CreateMap<TModel, TModel>();
}
}
The problem is occurring with ScannerConfiguration, which takes a single string parameter.
Here's the Autofac module I'm using:
public class AutoMapperModule : Module
{
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyTypes( assemblies )
.Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
.As<Profile>();
builder.Register( c => new MapperConfiguration( cfg =>
{
foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
{
cfg.AddProfile( profile );
}
} ) )
.AsSelf()
.SingleInstance();
builder.Register( c => c.Resolve<MapperConfiguration>().CreateMapper( c.Resolve ) )
.As<IMapper>()
.SingleInstance();
}
}
(thanx to http://www.protomatter.co.uk/blog/development/2017/02/modular-automapper-registrations-with-autofac/ for this).
I can successfully instantiate an IMapper, which shows the Autofac stuff is working properly. But when I attempt to call Map:
_onDisk = Mapper.Map<ScannerConfiguration>( _inMemory );
it fails with a "ScannerConfiguration has no parameterless constructor" exception.
Unfortunately, while I'm pretty sure I need to provide some options to that Map() call, I haven't been able to figure out how to do it. The parameter I need to pass in to the constructor is a public property of ScannerConfiguration, called SourceFilePath.
Since ScannerConfiguration requires a parameter, why don't you initialize it yourself?
var sc = new ScannerConfiguration("some string value");
_onDisk = Mapper.Map( _inMemory, sc );
If Automapper can't create an instance of the destination using a default constructor, you can give Automapper a function that calls a constructor and returns the new instance with ConstructUsing. After it constructs the object it continues mapping as usual.
For example here's a source and destination class. The destination class can't be created without calling a non-default constructor:
public class SourceClass
{
public string SourceStringProperty { get; set; }
public int OtherSourceProperty { get; set; }
public bool SameNameInBoth { get; set; }
}
public class DestinationClass
{
public DestinationClass(string destinationString)
{
DestinationStringPropertyFromConstructor = destinationString;
}
public string DestinationStringPropertyFromConstructor { get; }
public int OtherDestinationProperty { get; set; }
public bool SameNameInBoth { get; set; }
}
The mapping would look like this:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<SourceClass, DestinationClass>()
.ConstructUsing(hasString => new DestinationClass(hasString.SourceStringProperty))
.ForMember(dest => dest.OtherDestinationProperty,
opt => opt.MapFrom(src => src.OtherSourceProperty));
});
I added the other properties just to demonstrate that other than specifying a constructor, the other configuration details are all the same.
I am very new to C# and ServiceStack and I am working on a small project that consists on calling a third party API and loading the data I get back from the API into a relational database via ServiceStack's ORMLite.
The idea is to have each endpoint of the API have a reusable model that determines how it should be received in the API's response, and how it should be inserted into the database.
So I have something like the following:
[Route("/api/{ApiEndpoint}", "POST")]
public class ApiRequest : IReturn<ApiResponse>
{
public Int32 OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public String ApiEndpoint { get; set; }
}
public class ApiResponse
{
public Endpoint1[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
public class Endpoint1
{
[AutoIncrement]
public Int32 Id { get; set; }
[CustomField("DATETIME2(7)")]
public String PurchaseDate { get; set; }
[CustomField("NVARCHAR(50)")]
public String Customer { get; set; }
[CustomField("NVARCHAR(20)")]
public String PhoneNumber { get; set; }
public Int32 Amount { get; set; }
}
My first class represents the API's request with its route, the second class represents the API's response. The API's response is the same for all endpoints, but the only thing that varies is the structure of the Data field that comes back from that endpoint. I've defined the structure of one of my endpoints in my Endpoint1 class, and I am using it in my API's response class. As you can see, I am also defining a few attributes on my Endpoint1 class to help the ORM make better decisions later when inserting the data.
Ok, so the issue is that I have about 15 endpoints and I don't want to create 15 ApiResponse classes when I know the only thing that changes is that first Data field in the class.
So I made something like this:
public class DataModels
{
public Type getModel(String endpoint)
{
Dictionary<String, Type> models = new Dictionary<String, Type>();
models.Add("Endpoint1", typeof(Endpoint1));
// models.Add("Endpoint2", typeof(Endpoint2));
// models.Add("Endpoint3", typeof(Endpoint3));
// and so forth...
return models[endpoint];
}
}
I would like for getModel() to be called when the request is made so that I can pass in the ApiEndpoint field in the ApiRequest class and store the type that I want my Data field to have so that I can dynamically change it in my ApiResponse class.
In addition, there is the ORM part where I iterate over every endpoint and create a different table using the model/type of each endpoint. Something like this:
endpoints.ForEach(
(endpoint) =>
{
db.CreateTableIfNotExists<Endpoint1>();
// inserting data, doing other work etc
}
);
But again, I'd like to be able to call getModel() in here and with that define the model of the specific endpoint I am iterating on.
I've attempted calling getModel() on both places but I always get errors back like cannot use variable as a typeand others... so I am definitely doing something wrong.
Feel free to suggest a different approach to getModel(). This is just what I came up with but I might be ignoring a much simpler approach.
When I DID understand you correctly, you have different API-Calls which all return the same object. The only difference is, that the field "Data" can have different types.
Then you can simply change the type of data to object:
public object Data { get; set; }
And later simply cast this to the required object:
var data1=(Endpoint1[]) response.Data;
You're going to have a very tough time trying to dynamically create .NET types dynamically which requires advanced usage of Reflection.Emit. It's self-defeating trying to dynamically create Request DTOs with ServiceStack since the client and metadata services needs the concrete Types to be able to call the Service with a Typed API.
I can't really follow your example but my initial approach would be whether you can use a single Service (i.e. instead of trying to dynamically create multiple of them). Likewise with OrmLite if the Schema of the POCOs is the same, it sounds like you would be able to flatten your DataModel and use a single database table.
AutoQuery is an example of a feature which dynamically creates Service Implementations from just a concrete Request DTO, which is effectively the minimum Type you need.
So whilst it's highly recommended to have explict DTOs for each Service you can use inheritance to reuse the common properties, e.g:
[Route("/api/{ApiEndpoint}/1", "POST")]
public ApiRequest1 : ApiRequestBase<Endpoint1> {}
[Route("/api/{ApiEndpoint}/2", "POST")]
public ApiRequest2 : ApiRequestBase<Endpoint1> {}
public abstract class ApiRequestBase<T> : IReturn<ApiResponse<T>>
{
public int OrderId { get; set; }
public DateTime PurchaseDate { get; set; }
public string ApiEndpoint { get; set; }
}
And your Services can return the same generic Response DTO:
public class ApiResponse<T>
{
public T[] Data { get; set; }
public String ErrorCode { get; set; }
public Int32 ErrorNumber { get; set; }
public String ErrorDesc { get; set; }
}
I can't really understand the purpose of what you're trying to do so the API design is going to need modifications to suit your use-case.
You're going to have similar issues with OrmLite which is a Typed code-first POCO ORM where you're going to run into friction trying to use dynamic types which don't exist at Runtime where you'll likely have an easier time executing Dynamic SQL since it's far easier to generate a string than a .NET Type.
With that said GenericTableExpressions.cs shows an example of changing the Table Name that OrmLite saves a POCO to at runtime:
const string tableName = "Entity1";
using (var db = OpenDbConnection())
{
db.DropAndCreateTable<GenericEntity>(tableName);
db.Insert(tableName, new GenericEntity { Id = 1, ColumnA = "A" });
var rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "A"));
Assert.That(rows.Count, Is.EqualTo(1));
db.Update(tableName, new GenericEntity { ColumnA = "B" },
where: q => q.ColumnA == "A");
rows = db.Select(tableName, db.From<GenericEntity>()
.Where(x => x.ColumnA == "B"));
Assert.That(rows.Count, Is.EqualTo(1));
}
Which uses these extension methods:
public static class GenericTableExtensions
{
static object ExecWithAlias<T>(string table, Func<object> fn)
{
var modelDef = typeof(T).GetModelMetadata();
lock (modelDef)
{
var hold = modelDef.Alias;
try
{
modelDef.Alias = table;
return fn();
}
finally
{
modelDef.Alias = hold;
}
}
}
public static void DropAndCreateTable<T>(this IDbConnection db, string table)
{
ExecWithAlias<T>(table, () => {
db.DropAndCreateTable<T>();
return null;
});
}
public static long Insert<T>(this IDbConnection db, string table, T obj, bool selectIdentity = false)
{
return (long)ExecWithAlias<T>(table, () => db.Insert(obj, selectIdentity));
}
public static List<T> Select<T>(this IDbConnection db, string table, SqlExpression<T> expression)
{
return (List<T>)ExecWithAlias<T>(table, () => db.Select(expression));
}
public static int Update<T>(this IDbConnection db, string table, T item, Expression<Func<T, bool>> where)
{
return (int)ExecWithAlias<T>(table, () => db.Update(item, where));
}
}
But it's not an approach I'd take personally, if I absolutely needed (and I'm struggling to think of a valid use-case outside of table-based Multitenancy or sharding) to save the same schema in multiple tables I'd just be using inheritance again, e.g:
public class Table1 : TableBase {}
public class Table2 : TableBase {}
public class Table3 : TableBase {}
I know this question has already been asked but I couldn't find an answer that satisfied me. What I am trying to do is to retrieve a particular DbSet<T> based on its type's name.
I have the following :
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyDllAssemblyName")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyCallingAssemblyName")]
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
public dynamic GetByName_SwitchTest(string name) {
switch (name) {
case "A": return A;
case "B": return B;
}
}
public dynamic GetByName_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return model.GetValue(this);
return null;
}
}
I have no trouble getting the type itself whether it is via a simple switch or reflection. I need however to return the type as a dynamic since I do not know what DbSet type it will be.
Then somewhere else in the same assembly, I use it this way :
// MyDbContext MyDbContextInstance..
var model = MyDbContextInstance.GetByName_SwitchTest("A");
var record1 = model.FirstOrDefault(); // It crashes here with RunTimeBinderException
At this point model contains an instance of a InternalDbSet<ModelA> type. From there, any use I do with the model object I get a RunTimeBinderException :
'Microsoft.Data.Entity.Internal.InternalDbSet' does not contain a definition for 'FirstOrDefault'
Investigating on the web, I found a blog post explaining that (dixit his blog) :
the reason the call to FirstOrDefault() fails is that the type
information of model is not available at runtime. The reason it's not
available is because anonymous types are not public. When the method
is returning an instance of that anonymous type, it's returning a
System.Object which references an instance of an anonymous type - a
type whose info isn't available to the main program.
And then he points that a solution :
The solution is actually quite simple. All we have to do is open up
AssemplyInfo.cs of the ClassLibrary1 project and add the following
line to it: [assembly:InternalsVisibleTo("assembly-name")]
I did try this solution on my code but it doesn't work. For info I have an asp.net 5 solution with two assemblies running on dnx dotnet46. An app and a dll containing all my models and DbContext. All the concerned calls I do are located on the dll though.
Does this solution have any chance to work ?
Am I missing something ?
Any pointers would be greatly appreciated ?
Thanks in advance
[EDIT]
I have tried to return IQueryable<dynamic> rather than dynamic and I could do the basic query model.FirstOrDefault(); but above all I'd like to be able to filter on a field too :
var record = model.FirstOrDefault(item => item.MyProperty == true);
So how did I do it when I am not aware of <T> during compile time.
First need to get the type as DbContext.Set method returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store.
public virtual DbSet Set(Type entityType)
Note here argument is the type of entity for which a set should be returned.And set for the given entity type is the return value.
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == <Pass your table name>);
now once I have this type
if(type != null)
{
DbSet context = context.Set(type);
}
Or a one liner would be
DbSet mySet = context.Set(Type.GetType("<Your Entity Name>"));
*Disclaimer: This response doesn't give a stricto sensu answer to my question. It is rather a different approach to resolve my own problem. I am aware this is a specific example for a given situation that will not work for everyone. I am posting this approach in the hope it helps someone but will not mark it as the answer as I am still hoping for a real solution.
To start with, let's accept the fact that the only useful information we can get out of the current code is whether a record exists or not.. Any attempt of a dynamic queries after that would give the RuntimeBinderException.
Then let's continue with another fact; DbContext.Add(object) and DbContext.Update(object) are not template based so we can use them to save our models ( Instead of db.A.Add() or db.A.Update() )
In my own situation, no more is required to work out a procedure
Define models a little differently
To start with, I need a field that is retrievable across all my models which should obviously be a way to identify a unique record.
// IModel give me a reliable common field to all my models ( Fits my DB design maybe not yours though )
interface IModel { Guid Id { get; set; } }
// ModelA inherit IModel so that I always have access to an 'Id'
class ModelA : IModel {
public Guid Id { get; set; }
public int OtherField { get; set; }
}
// ModelB inherit IModel so that I always have access to an 'Id'
class ModelB : IModel {
public Guid Id { get; set; }
public string WhateverOtherField { get; set; }
}
Re-purpose the dynamic queries a bit to do something we know works
I haven't found a way to do smart query dynamically, so instead I know I can reliably identify a record and know if it exists or not.
class MyDbContext : DbContext {
public DbSet<ModelA> A { get; set; }
public DbSet<ModelB> B { get; set; }
// In my case, this method help me to know the next action I need to do
// The switch/case option is not pretty but might have better performance
// than Reflection. Anyhow, this is one's choice.
public bool HasRecord_SwitchTest(string name) {
switch (name) {
case "A": return A.AsNoTracking().Any(o => o.Id == id);
case "B": return B.AsNoTracking().Any(o => o.Id == id);
}
return false;
}
// In my case, this method help me to know the next action I need to do
public bool HasRecord_ReflectionTest(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
return (bool)model.GetValue(this).AsNoTracking().Any(o => o.Id == id);
return false;
}
// Update and save immediately - simplified for example
public async Task<bool> UpdateDynamic(object content)
{
EntityEntry entry = Update(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
// Insert and save immediately - simplified for example
public async Task<bool> InsertDynamic(object content)
{
EntityEntry entry = Add(content, GraphBehavior.SingleObject);
return 1 == await SaveChangesAsync(true);
}
}
A little bit of plumbing to give a sense to my situation
Next, what I needed to do with that dynamic queries was a way to replicate data from a server down to my client. ( I have omitted a big chunk of the architecture to simplify this example )
class ReplicationItem
{
public ReplicationAction Action { get; set; } // = Create, Update, Delete
public string ModelName { get; set; } // Model name
public Guid Id { get; set; } // Unique identified across whole platform
}
Connecting the bits.
Now, here's the routine that connects the bits
public async void ProcessReplicationItem(ReplicationItem replicationItem)
{
using (var db = new MyDbContext())
{
// Custom method that attempts to get remote value by Model Name and Id
// This is where I get the strongly typed object
var remoteRecord = await TryGetAsync(replicationItem.ModelName, replicationItem.Id);
bool hasRemoteRecord = remoteRecord.Content != null;
// Get to know if a local copy of this record exists.
bool hasLocalRecord = db.HasRecord_ReflectionTest(replicationItem.ModelName, replicationItem.Id);
// Ensure response is valid whether it is a successful get or error is meaningful ( ie. NotFound )
if (remoteRecord.Success || remoteRecord.ResponseCode == System.Net.HttpStatusCode.NotFound)
{
switch (replicationItem.Action)
{
case ReplicationAction.Create:
{
if (hasRemoteRecord)
{
if (hasLocalRecord)
await db.UpdateDynamic(remoteRecord.Content);
else
await db.InsertDynamic(remoteRecord.Content);
}
// else - Do nothing
break;
}
case ReplicationAction.Update:
[etc...]
}
}
}
}
// Get record from server and with 'response.Content.ReadAsAsync' type it
// already to the appropriately
public static async Task<Response> TryGetAsync(ReplicationItem item)
{
if (string.IsNullOrWhiteSpace(item.ModelName))
{
throw new ArgumentException("Missing a model name", nameof(item));
}
if (item.Id == Guid.Empty)
{
throw new ArgumentException("Missing a primary key", nameof(item));
}
// This black box, just extrapolate a uri based on model name and id
// typically "api/ModelA/{the-guid}"
string uri = GetPathFromMessage(item);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:12345");
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return new Response()
{
Content = await response.Content.ReadAsAsync(Type.GetType(item.ModelName)),
Success = true,
ResponseCode = response.StatusCode
};
}
else
{
return new Response()
{
Success = false,
ResponseCode = response.StatusCode
};
}
}
}
public class Response
{
public object Content { get; set; }
public bool Success { get; set; }
public HttpStatusCode ResponseCode { get; set; }
}
ps: I am still interested in a real answer, so please keep posting for other answer if you have a real one to share.
You could use this to get the DBSet for a specific type:
public object GetByType(DbContextcontext, Type type) {
var methode = _context.GetType().GetMethod("Set", types: Type.EmptyTypes);
if (methode == null) {
return null;
}
return methode.MakeGenericMethod(type).Invoke(_context, null);
}
Does anyone know why this works:
Mapper.Configuration.RecognizeDestinationPrefixes("Foo");
Mapper.CreateMap<A, B>();
But this doesn't:
Mapper.CreateProfile("FooPrefix").RecognizeDestinationPrefixes("Foo");
Mapper.CreateMap<A, B>()
.WithProfile("FooPrefix");
?
While this question is quite old now, I thought it would be useful to answer it given I spent ages trying to get profiles to work.
Although there are a bunch of ways to configure profiles, it seems that the only way what I could get it to work was as follows:
public class ExampleProfile : Profile
{
protected override void Configure()
{
ReplaceMemberName("Z", "A");
CreateMap<Source, Destination>(); // Notice this is CreateMap, NOT Mapper.CreateMap...
}
public override string ProfileName
{
get { return this.GetType().Name; }
}
}
Then, set up the profile in your config:
Mapper.Initialize(cfg => cfg.AddProfile<ExampleProfile>());
Given the Source and Destination classes as follows:
public class Source
{
public string Zabc { get; set; }
}
public class Destination
{
public string Aabc { get; set; }
}
This should now work:
var source = new Source { Zabc = "source" };
var dest = Mapper.Map<Destination>(source);
Assert.AreEqual(source.Zabc, dest.Aabc);
Profile names are different. You use FooxPrefix when creating the profile and then use FooPrefix when creating the map.