I have a MySql database with columns Id int and Name:json
Places Table Sample
Id Name
1 {"en":"Sphinx","ar":"أبو الهول","fr":"Le sphinx"}
C# Place class
public class Place
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
}
I'm connecting with EntityFramework 6 and connection success and retrieve data like this
{Id = 1, Name = "{\"en\":\"Sphinx\", \"ar\":\"أبو الهول\", \"fr\":\"Le sphinx\"}" }
What I want how to Map Name to new Object not JSON string
something like this
Place class
public class Place
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public Localized<string> Name { get; set; }
}
Localized class
public class Localized<T>
{
public T en { get; set; } // english localization
public T ar { get; set; } // arabic localization
public T fr { get; set; } // french localization
}
when I do this Name property come with NULL value
Code in Repository
using (var context = new PlacesEntityModel())
{
return context.Places.Take(5).ToList();
}
I don't want to use AutoMapper,
I want something in EntityFramework to select only one language in Database Level without fetching all other data and then map it
how to fix this?
You can try extension method to map from your entity type.
public class Place
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
}
public class PlaceDTO
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public Localized<string> Name { get; set; }
}
public class Localized<T>
{
public T en { get; set; } // english localization
public T ar { get; set; } // arabic localization
public T fr { get; set; } // french localization
}
Extenstion Method ToDto
public static class Extensions
{
public static PlaceDTO ToDto(this Place place)
{
if (place != null)
{
return new PlaceDTO
{
Id = place.Id,
Name = JsonConvert.DeserializeObject<Localized<string>>(place.Name)
};
}
return null;
}
}
Usage
var place = new Place() { Id = 1, Name = "{\"en\":\"Sphinx\", \"ar\":\"أبو الهول\", \"fr\":\"Le sphinx\"}" };
var placeDTO = place.ToDto();
Console.WriteLine($"{placeDTO.Id}-{placeDTO.Name.ar}-{placeDTO.Name.en}-{placeDTO.Name.fr}");
First of all, by using a class with a property per language, you restrict yourself. You'd always have to add new properties if you add new languages, which would of course be feasible, but unnecessary complicated. Furthermore you'd usually have the language as a string-ish object (or be able to convert), hence this would lead to code like this
Localized<string> name = ...;
switch(language)
{
case "en":
return name.en;
case "ar":
return name.ar;
case "fr":
return name.fr;
default:
throw new LocalizationException();
}
which is error-prone and overly complicated. For your problem, I think I'd opt to use some kind of dictionary
IDictionary<string, string> names = ...;
if(names.ContainsKey(language))
{
return names[language];
}
else
{
throw new LocalizationException();
}
which is easily extensible by just adding more translations to the dictionary.
To convert your JSON string to an IDcitionary<string, string>, you could use the following code
localizedNames = JObject.Parse(Name)
.Children()
.OfType<JProperty>()
.ToDictionary(property => property.Name,
property => property.Value.ToString());
From within your class this would effectively be
public class Place
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
public Dictionary<string, string> LocalizedNames
{
get
{
return JObject.Parse(Name)
.Children()
.OfType<JProperty>()
.ToDictionary(property => property.Name,
property => property.Value.ToString());
}
}
}
The localized values can be accessed like
var localizedPlaceName = place.LocalizedNames[language];
Please note: Depending on your needs and use cases, you should consider the following issues:
Caching
In my snippet, the JSON string is parsed every time the localized names are accessed. Depending on how often you access it, this might be detrimental to performance, which could be mitigated by caching the result (don't forget to delete the cache when Name is set).
Separation of concerns
The class as is is supposed to be a pure model class. You might want to introduce domain classes that encapsulate the presented logic, rather than adding the logic to the model class. Having a factory that creates readily localized objects based on the localizable object and the language could be an option, too.
Error handling
In my code there is no error handling. Depending on the reliability of input you should consider additional error handling.
devart.com/dotconnect/mysql/docs/EF-JSON-Support.html
Like what #Nkosi said
In that case then, take a look at this article devart.com/dotconnect/mysql/docs/EF-JSON-Support.html
It probably can given that the library was able to build that feature in. You would need to figure out what they they did (reverse engineer)
I usually just use JSON.Net, I notice that another answer referenced JObject, but without going into whether your data-model is the right model, I generally find that you can do:
var MyObjectInstance = JObject.Parse(myJsonString).ToObject<MyObjectType>();
I notice that you have ComponentModel attributes on your class. I don't know off hand how many of these JSon.Net supports, and you'd have to research that. It definitely supports some attributes from XML serialization, and also has some of it's own.
Note that you can also convert a JSOn array into a list:
var MyObjectList = JArray.Parse(myJsonString).ToObject<IEnumerable<MyObjectType>();
I want something in EntityFramework to select only one language in
Database Level without fetching all other data and then map it
if you want it to be from database level, you can always create a view and then include this view in your project.
Example :
CREATE VIEW `PlacesLocalized` AS
SELECT
Id
, TRIM(REPLACE(name->'$.en', '"','')) AS en
, TRIM(REPLACE(name->'$.ar', '"','')) AS ar
, TRIM(REPLACE(name->'$.fr', '"','')) AS fr
FROM
places
This would create a model class Like :
public class PlacesLocalized
{
public int Id { get; set; }
public string en {get; set;}
public string ar {get; set;}
public string fr {get; set;}
}
Then, you can do :
var places = context.PlacesLocalized.Where(x=> x.en == "Sphinx");
But if you don't have enough permissions to do this in the database level, then you would need to specify the query in your EF. There is no easy way to change the execution logic of Entity Framework just for specific classes. That's why Entity Framework included SqlQuery method, which would give more flexibility to have custom queries when needed (like yours).
So, if you need to specify the localization from Entity Framework, then you would do a repository class to specify all custom queries you need including creating any DTO needed.
The basic way would be something like this :
public enum Localized
{
English,
Arabic,
French
}
public class PlaceRepo : IDisposable
{
private readonly PlacesEntityModel _context = new PlacesEntityModel();
public List<Place> GetPlacesLocalized(Localized localized = Localized.English)
{
string local = localized == Localized.Arabic ? "$.ar"
: localized == Localized.French ? "$.fr"
: "$.en";
return _context.Places.SqlQuery("SELECT Id, name-> #p0 as Name FROM places", new[] { local })
.Select(x=> new Place { Id = x.Id, Name = x.Name.Replace("\"", string.Empty).Trim() })
.ToList();
}
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
_disposed = true;
}
}
~PlaceRepo()
{
Dispose(false);
}
}
now, you can do this :
using(var repo = new PlaceRepo())
{
var places = repo.GetPlacesLocalized(Localized.Arabic);
}
public class Place
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
public static explicit operator Place(PlaceDTO dto)
{
return new Place()
{
Id = dto.Id,
Name = dto.Name
};
}
}
public class PlaceDTO
{
[Key, Column("id")]
public int Id { get; set; }
[Column("name")]
public Localized<string> Name { get; set; }
public static explicit operator PlaceDTO(Place pls)
{
return new PlaceDTO()
{
Id = pls.Id,
Name = pls.Name
};
}
}
var placeDTO = (placeDto)place;
we can achieve this using explicit operator without using auto mapper
Related
I have created a class and I'm putting a list of same type as a property of that class.
Is it good or bad practice?
I am putting the same type of list because of I want to manage everything by only one object.
I don't want to create a single object and a list of object of the same type.
Any help is highly appreciated!
class AssetSection
{
public string Code { get; set; }
public string Description { get; set; }
public string SITEID { get; set; }
public string PlantID { get; set; }
public string User { get; set; }
public string UpDateTime { get; set; }
public List<AssetSection> AssetSections { get; set; }
public AssetSection(string des, string code)
{
Description = des;
Code = code;
}
}
That's ok. If you can imagine, you can design and use it.
Let's talk about entity framework. We create 2 entities like this:
public class User : IdentityUser
{
[Key]
public string Id { get; set; }
public UserProfile Profile { get; set; }
}
public class UserProfile
{
[Key]
public string UserId { get; set; }
public User User { get; set; }
}
Now, when we try to get current user:
User user = await _userManager.GetUserAsync(User);
user becomes an instance of User class now. This instance has a property name Profile, and this property has another property name User which has a type User.
It's called mapping. So, to answer your question: You can use it. But I'm not saying it's good or not based on the way to design the model.
As a general observation, such a structure is known as a rose tree, or just a tree. It enables you to write code like this:
var t = new AssetSection("foo", "bar")
{
AssetSections = new List<AssetSection>
{
new AssetSection("baz", "qux")
{
new AssetSection("corge", "garply"),
new AssetSection("fred", "plugh")
{
AssetSections = new List<AssetSection>
{
new AssetSection("xyzzy", "thud")
}
}
},
new AssetSection("quux", "quuz")
{
new AssetSection("grault", "waldo")
}
}
};
If what you want to model is a tree-like structure like that, then it's fine. On the other hand, if such a hierarchy is not what you're trying to model, then it's likely to be confusing.
By the way, the code as proposed violates the .NET framework design guidelines:
DO NOT provide settable collection properties.
DO NOT use ArrayList or List<T> in public APIs
Suppose you have this source model:
public abstract class SourceModelBase {
}
public class SourceContact : SourceModelBase {
public string FirstName { get; set; }
public string LastName { get; set; }
public KeyValuePair Pair { get; set; }
public SourceAddress Address { get; set; }
}
public class KeyValuePair { // Not derived from SourceModelBase.
public string Key { get; set; }
public string Value { get; set; }
}
public class SourceAddress : SourceModelBase {
public string StreetName { get; set; }
public string StreetNumber { get; set; }
}
Now the destination model should be mapped 1:1 by default (subject to normal AutoMapper configuration), but each thing derived from SourceModelBase should be mapped to a wrapper class class Wrap<T> { T Payload { get; set; } string Meta { get; set; } }.
public abstract class DestinationModelBase {
}
public class DestinationContact : DestinationModelBase {
public string FirstName { get; set; }
public string LastName { get; set; }
public KeyValuePair Pair { get; set; } // Not wrapped, base class not `SourceModelBase`.
public Wrap<DestinationAddress> Address { get; set; }
}
public class DestinationAddress : DestinationModelBase {
public string StreetName { get; set; }
public string StreetNumber { get; set; }
}
Since the contact class itself is derived from SourceModelBase it should be wrapped as well.
The result should have this structure:
Wrap<DestinationContact> Contact
string Meta // Comes from the custom wrapper logic.
DestinationContact Payload
string FirstName
string LastName
KeyValuePair Pair
string Key
string Value
Wrap<DestinationAddress> Address
string Meta // Comes from the custom wrapper logic.
DestinationAddress Payload
string StreetName
string StreetNumber
Obviously this wrapping should nest, illustrated by the fact that the mapped object itself is subject to it and so is its Address property.
For some reason all I keep finding are questions related to mapping from destination to source. I know I have to somehow use ResolveUsing and if the destination type is derived from SourceModelBase, somehow apply custom logic to provide the Wrap<T> value based on the value of the source property.
I don't know where to start at all, though. Especially when the source object itself is specified to be subject of the wrapping logic as well.
What's the best, most AutoMapper-idiomatic way to wrap the nested objects if they meet a condition and at the same time wrap the original object as well if it meets the same condition? I already have the mapper creation abstracted away so I can mold the original object automatically before passing it to the mapper, which may help with subjecting the original object to the resolver as well by doing mapper.Map(new { Root = originalObject }) so the resolver sees the instance of the original object as if it was a value of a property of source object as well, not the source object itself.
According to this issue on AutoMapper GitHub page, there is no direct way to do it.
But there is some workarounds. For example - reflection.
In this case you need to know wrapper type and implement converter for desired types. In this example it's MapAndWrapConverter from TSource to Wrap<TDestination>
CreateWrapMap method creates two bindings:
SourceAddress -> Wrap<DestinationAddress> and SourceContact -> Wrap<DestinationContact> which allow you to map SourceContant to wrapped DestinationContact.
internal class Program
{
public static void Main()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SourceAddress, DestinationAddress>();
cfg.CreateMap<SourceContact, DestinationContact>();
cfg.CreateWrapMap(
//func selecting types to wrap
type => typeof(DestinationModelBase).IsAssignableFrom(type)
&& !type.IsAbstract,
typeof(Wrap<>),
typeof(MapAndWrapConverter<,>));
});
var mapper = config.CreateMapper();
//Using AutoFixture to create complex object
var fixture = new Fixture();
var srcObj = fixture.Create<SourceContact>();
var dstObj = mapper.Map<Wrap<DestinationContact>>(srcObj);
}
}
public static class AutoMapperEx
{
public static IMapperConfigurationExpression CreateWrapMap(
this IMapperConfigurationExpression cfg,
Func<Type, bool> needWrap, Type wrapperGenericType,
Type converterGenericType)
{
var mapperConfiguration =
new MapperConfiguration((MapperConfigurationExpression)cfg);
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var dstType in types.Where(needWrap))
{
var srcType = mapperConfiguration.GetAllTypeMaps()
.Single(map => map.DestinationType == dstType).SourceType;
var wrapperDstType = wrapperGenericType.MakeGenericType(dstType);
var converterType = converterGenericType.MakeGenericType(srcType, dstType);
cfg.CreateMap(srcType, wrapperDstType)
.ConvertUsing(converterType);
}
return cfg;
}
}
public class MapAndWrapConverter<TSource, TDestination>
: ITypeConverter<TSource, Wrap<TDestination>>
{
public Wrap<TDestination> Convert(
TSource source, Wrap<TDestination> destination, ResolutionContext context)
{
return new Wrap<TDestination>
{
Payload = context.Mapper.Map<TDestination>(source)
};
}
}
CreateWrapMap method is a little bit messy, especially the part with finding matching types. But it can be refined according to your needs.
I have a problem where I create an object containing a list, load it into my database, run a query that returns the object, but find the list null. All other properties of the object are as they should be. I'm using a list called "Ints" that is filled with a few integers but I've tried using other types.
Here's my model:
public class CourseModel
{
public int CourseModelId { get; set; }
public virtual ICollection<int> Ints { get; set; } // the variable in question
public string Name { get; set; }
public string Overview { get; set; }
}
And here's my database population (The database is called LearnYou):
public class LearnYouDbContextInitializer : DropCreateDatabaseAlways<LearnYouDbContext>
{
protected override void Seed(LearnYouDbContext context)
{
context.Courses.Add(new CourseModel()
{
Name = "C# Programming",
Overview = "You'll learn some C#",
Ints = new List<int> { 1, 42, 3 },
});
context.SaveChanges();
}
}
Here's the controller code for querying the object:
// GET: Course/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
CourseModel courseModel = db.Courses.Find(id);
// DEBUGGING THE PREVIOUS LINE SHOWS INTS IS NULL
if (courseModel == null)
{
return HttpNotFound();
}
return View(courseModel);
}
The "Ints" property is not null after saving the context in the database population part but is always null when it's queried (I visit the page ~Edit/1 to debug). I just can't figure out why when all other properties are fine. Any ideas? Thanks.
An ICollection in a model indicates a Parent->Child relationship. However, I doubt EF will be able to determine how to create a child table for an ICollection of integers. Here is what I would do.
Create a new model Ints (or whatever it actually represents):
public class Ints {
public int Value { get; set;}
}
Modify your original model to use it:
public class CourseModel
{
public int CourseModelId { get; set; }
public virtual ICollection<Ints> Ints { get; set; } // See the difference?
public string Name { get; set; }
public string Overview { get; set; }
}
That should make it work.
It Is not working because you are mapping directly to a int primitive type of .net and Entity Framework doesn't allow it.
In this case what you can do is create your onw object for example and sql table like
public class Ints {
{
public Course Course { get; set; }
public int IntValue { ger; set ; }
}
And referencing it from CourseModel
public virtual List<Ints> Ints { get; set; }
I'm trying to use AutoMapper to take data from a class that has prefixes before property names and map it to a second class that doesn't have those prefixes. However, I don't necessarily want it to always strip out that prefix: I just want it to do it for this particular mapping.
My source class looks like this:
public class AdvancedSearchFilterDataModel
{
// ....
public string ServiceMeterNumber { get; set; }
// ....
}
My destination class looks like this:
[DataContract]
public class ServicesAdvancedSearchFilterData : AdvancedSearchFilterData
{
// ....
[DataMember]
public string MeterNumber { get; set; }
// ....
}
When I try to map values like this, it works:
Mapper.Configuration.RecognizePrefixes("Service");
Mapper.CreateMap<AdvancedSearchFilterDataModel, ServicesAdvancedSearchFilterData>();
ServicesAdvancedSearchFilterData servciesFilterData =
Mapper.Map<ServicesAdvancedSearchFilterData>(model);
But I only want "Service" to be recognized as a prefix for certain mappings, since it's also used as a normal part of property names in other mappings. I tried to handle this with a profile, but this didn't work -- no data was mapped:
Mapper.CreateProfile("ServicePrefix").RecognizePrefixes("Service");
Mapper.CreateMap<AdvancedSearchFilterDataModel, ServicesAdvancedSearchFilterData>()
.WithProfile("ServicePrefix");
ServicesAdvancedSearchFilterData servciesFilterData =
Mapper.Map<ServicesAdvancedSearchFilterData>(model);
How can I make it recognize the prefix only when I want it to, either using profiles or some other technique? (I also have other prefixes that I'm going to need it to recognize for other mappings in the same way.)
I achieved this functionality by creating following structure:
I have Person model for my view which is flattened from PersonCombined
public class PersonCombined
{
public Person Person { get; set; }
public Address DefaultAddress { get; set; }
public Contact EmailContact { get; set; }
public Contact PhoneContact { get; set; }
public Contact WebsiteContact { get; set; }
}
public class Person : IWebServiceModel
{
public int ID { get; set; }
public string PersonFirstName { get; set; }
public string PersonSurname { get; set; }
public string PersonDescription { get; set; }
public Nullable<bool> PersonIsActive { get; set; }
}
Then I have separate class for this mapping only that looks like this:
public class PersonCustomMapping : ICustomMapping
{
const string separator = " ";
private static IMappingEngine _MappingEngine;
public IMappingEngine MappingEngine
{
get
{
if (_MappingEngine == null)
{
var configuration = new ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
configuration.RecognizePrefixes("Person");
configuration.RecognizeDestinationPrefixes("Person");
configuration.CreateMap<Person, MCIACRM.Model.Combine.PersonCombined>();
configuration.CreateMap<MCIACRM.Model.Combine.PersonCombined, Person>();
_MappingEngine = new MappingEngine(configuration);
}
return _MappingEngine;
}
}
}
In my generic view I have mappingEngine property like this:
private IMappingEngine mappingEngine
{
get
{
if (_mappingEngine == null)
{
_mappingEngine = AutoMapper.Mapper.Engine;
}
return _mappingEngine;
}
}
Finally in my generic view constructor i have:
public GenericEntityController(IGenericLogic<S> logic, ICustomMapping customMapping)
: base()
{
this._mappingEngine = customMapping.MappingEngine;
this.logic = logic;
}
And that's how I do mapping:
result = items.Project(mappingEngine).To<R>();
or
logic.Update(mappingEngine.Map<S>(wsItem));
Because I use 1 entity per view I can define custom mapping configuration per entity.
Hope this helps
Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.