I'm using Fluent Assertions to Validate to different test Objects
public class DTO
{
public int Key {get; set;}
public string Code { get; set; }
}
public class KeyDTO
{
public int Id {get; set;}
public string Code { get; set; }
}
Note: this is not an exact replica of the code there are more field in the Original DTO but they're not necessary to explain the problems
I'm creating a function to assert that they are equal I'm trying use fluent assertions to do so. I Can't figure out a way to say that the Id Maps To the Key.
public void AssertDTOsAreEqual( List<DTO> orderedDTOs, List<KeyDTO> orderedKeys)
{
orderedDTOs.ShouldAllBeEquivalentTo(orderedKeys, o => o/*??*/)
}
Note: I Know as an alternative I can do this by zipping the ordered collections and comparing each property, but for more lengthy DTO's this would be trouble doing compairisons for each property.
Does anyone know of a way to map different properties in the ShouldAllBeEquivalentTo. Or Perhaps a better way to do this in general?
Unfortunately not yet. But this my personal number one on my list of features to add. I hope to get some time soon.
subjectCollection.Should().AllBeEquivalentTo(expected) has now been implemented in FluentAssertions:
https://fluentassertions.com/documentation/#collections-and-dictionaries
My apologies, I misread the question. The best I can come up with in the current version of FluentAssertions is to project the expected collection using Linq's .Select and compare to the new objects:
subjectCollection.Should().BeEquivalentTo(expectedCollection.Select(o => new { Id = o.Key }));
Related
Let me foreword this by saying this is my first real experience with both Entity Framework and relational databases in general. If I am doing it completely wrong, please tell me.
I want my data structured as something like this (Cut down on the "extra" code):
Indicators {
int SomeText1TranslationRef
List<Translation> SomeText1Translations
int SomeText2TranslationRef
List<Translation> SomeText2Translations
}
Measures {
int SomeText3TranslationRef
List<Translation> SomeText3Translations
int SomeText3TranslationRef
List<Translation> SomeText4Translations
}
Translation {
Int TranslationID
String LanguageCode
String Text
}
So in essence, the indicators table would have a list of SomeText1 Translations as well as SomeText2, all joined using the TranslationID through the "Ref" properties.
I have the translation properties annotated with [ForeignKey("....Ref")].
I expected this to work magically as the rest of the framework seems to, but instead the translation table gets columns named "SomeText1TranslationRef" and "SomeText2TranslationRef".
Am I doing this wrong?
I am looking at other features of Entity Framework and see an annotation for "InverseProperty". Is it something which may help?
I'm not 100% clear on your goal, but if an Indicator can have many Text1 translations and many Text2 translations, then that is 2 many-to-many relationships. Same for Measures. EF will need a join/bridge/junction table for this (IndicatorTranslation and MeasureTranslation). You can explicitly create this table, or let EF do it behind the scenes:
Indicator {
// other indicator fields
public virtual List<Translation> SomeText1Translations
public virtual List<Translation> SomeText2Translations
}
Measure {
// other measure fields
public virtual List<Translation> SomeText3Translations
public virtual List<Translation> SomeText4Translations
}
Translation {
Int TranslationID
String LanguageCode
String Text
// Use inverse attributes or fluent code to tell EF how to connect relationships
[InverseProperty("SomeText1Translations")]
public virtual ICollection<Indicator> TranslationForIndicatorText1 { get; set; }
[InverseProperty("SomeText2Translations")]
public virtual ICollection<Indicator> TranslationForIndicatorText2 { get; set; }
[InverseProperty("SomeText3Translations")]
public virtual ICollection<Measure> TranslationForMeasureText3 { get; set; }
[InverseProperty("SomeText4Translations")]
public virtual ICollection<Measure> TranslationForMeasureText4 { get; set; }
}
I'm happy to be corrected if I'm wrong since it's nothing I've tried for quite a while, but as far as I'm aware, EF is still not able to create relationships from one property on a type to two different other types, or vice versa, even with constraints that would make it valid.
In your case, you would end up with the 4 navigation properties being required on your translation. (int IndicatorRef1, int IndicatorRef2, int MeasureRef3, int MeasureRef4). Most wouldn't call it a dream scenario.
I asked a similar question a couple of years ago, and have since then sort of concluded that i was foolish trying to get EF to solve all my problems.
So here's an answer to what you're trying to achieve, and perhaps even a solution to 2 of your questions:
Don't rely on EF handle any scenario. Actually, pretty much don't rely on EF to handle relationships at all other than 1-1, 1-* or *-*. And some forms of inheritance.
In most other cases, you will end up with one navigation property for each type you're trying to reference, with data being populated with nulls for each navigation property but the one specifically targeted.
The good news? You don't have to rely on EF for it. The main advantage of EF is it's productivity. For certain cases, it's still worth leveraging EF, but providing your own methods of productivity. If you want to get a set of indicators with 2 collections of translations based on a ref, simply create a method that provides it.
Something like
public IQueryable<Indicators> SetOfIndicatorsWithTranslations()
{
// Untested query that might need some fixing in an actual implementation
return ctx.Set<Indicators>().Select(ind => new Indicators() {
Text1Ref= ind.Text1Ref, // whatever the property is
Text1RefList = ctx.Set<Translation>().Where(t => t.TranslationId == ind.Text1Ref),
Text2Ref= ind.Text2Ref,
Text2RefList = ctx.Set<Translation>().Where(t => t.TranslationId == ind.Text2Ref),
});
}
Now that's a query EF will handle for you gracefully.
There are of course a lot more elegant solutions to something like it. The important part is really that it's sometimes worth doing it yourself rather than restricting yourself to the capabilities of your tool of choice. (Well, at least that's the important part that I eventually learned :) )
Long story short, the caveat is the "Core" part of .Net Core. EF Core does not support convention-over-configuration many-to-many relationships yet (See here).
The only way to achieve this is to manually create the junction tables as Steve suggested. Here is all the information needed: https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration
In previous versions of Entity Framework, this model definition was sufficient for EF to imply the correct type of relationship and to generate the join table for it. In EF Core 1.1.0, it is necessary to include an entity in the model to represent the join table, and then add navigation properties to either side of the many-to-many relations that point to the join entity instead:
The above link will most likely be updated with time so for context purposes, here is the code which goes along with it:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class BookCategory
{
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Alternatively, using Fluent:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BookCategory>()
.HasKey(bc => new { bc.BookId, bc.CategoryId });
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Book)
.WithMany(b => b.BookCategories)
.HasForeignKey(bc => bc.BookId);
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Category)
.WithMany(c => c.BookCategories)
.HasForeignKey(bc => bc.CategoryId);
}
Consider having a ViewModel:
public class ViewModel
{
public int id { get; set; }
public int a { get; set; }
public int b { get; set; }
}
and an original Model like this:
public class Model
{
public int id { get; set; }
public int a { get; set; }
public int b { get; set; }
public int c { get; set; }
public virtual Object d { get; set; }
}
Each time I get the view model I have to put all ViewModel properties one by one into Model. Something like:
var model = Db.Models.Find(viewModel.Id);
model.a = viewModel.a;
model.b = viewModel.b;
Db.SaveChanges();
Which always cause lots of problems. I even sometimes forget to mention some properties and then disaster happens!
I was looking for something like:
Mapper.Map(model, viewModel);
BTW: I use AutoMapper only to convert Model to ViewModel but vice-versa I always face errors.
Overall that might be not the answer, that you are looking for, but here's a quote from AutoMapper author:
I can’t for the life of me understand why I’d want to dump a DTO
straight back in to a model object.
I believe best way to map from ViewModel to Entity is not to use AutoMapper for this. AutoMapper is a great tool to use for mapping objects without using any other classes other than static. Otherwise, code gets messier and messier with each added service, and at some point you won't be able to track what caused your field update, collection update, etc.
Specific issues often faced:
Need for non-static classes to do mapping for your entities
You might need to use DbContext to load and reference entities, you might also need other classes - some tool that does image upload to your file storage, some non-static class that does hashing/salt for password, etc etc... You either have to pass it somehow to automapper, inject or create inside AutoMapper profile, and both practices are pretty troublemaking.
Possible need for multiple mappings over same ViewModel(Dto) -> Entity Pair
You might need different mappings for same viewmodel-entity pair, based on if this entity is an aggregate, or not + based on if you need to reference this entity or reference and update. Overall this is solvable, but causes a lot of not-needed noise in code and is even harder to maintain.
Really dirty code that's hard to maintain.
This one is about automatic mapping for primitives (strings, integers, etc) and manual mapping references, transformed values, etc. Code will look really weird for automapper, you would have to define maps for properties (or not, if you prefer implicit automapper mapping - which is also destructive when paired with ORM) AND use AfterMap, BeforeMap, Conventions, ConstructUsing, etc.. for mapping other properties, which complicates stuff even more.
Complex mappings
When you have to do complex mappings, like mapping from 2+ source classes to 1 destination class, you will have to overcomplicate things even more, probably calling code like:
var target = new Target();
Mapper.Map(source1, target);
Mapper.Map(source2, target);
//etc..
That code causes errors, because you cannot map source1 and source2 together, and mapping might depend on order of mapping source classes to target. And I'm not talking if you forget to do 1 mapping or if your maps have conflicting mappings over 1 property, overwriting each other.
These issues might seem small, but on several projects where I faced usage of automapping library for mapping ViewModel/Dto to Entity, it caused much more pain than if it was never used.
Here are some links for you:
Jimmy Bogard, author of AutoMapper about 2-way mapping for your entities
A small article with comments about problems faced when mapping ViewModel->Entity with code examples
Similar question in SO: Best Practices For Mapping DTO to Domain Object?
For this purpose we have written a simple mapper. It maps by name and ignores virtual properties (so it works with entity framework). If you want to ignore certain properties add a PropertyCopyIgnoreAttribute.
Usage:
PropertyCopy.Copy<ViewModel, Model>(vm, dbmodel);
PropertyCopy.Copy<Model, ViewModel>(dbmodel, vm);
Code:
public static class PropertyCopy
{
public static void Copy<TDest, TSource>(TDest destination, TSource source)
where TSource : class
where TDest : class
{
var destProperties = destination.GetType().GetProperties()
.Where(x => !x.CustomAttributes.Any(y => y.AttributeType.Name == PropertyCopyIgnoreAttribute.Name) && x.CanRead && x.CanWrite && !x.GetGetMethod().IsVirtual);
var sourceProperties = source.GetType().GetProperties()
.Where(x => !x.CustomAttributes.Any(y => y.AttributeType.Name == PropertyCopyIgnoreAttribute.Name) && x.CanRead && x.CanWrite && !x.GetGetMethod().IsVirtual);
var copyProperties = sourceProperties.Join(destProperties, x => x.Name, y => y.Name, (x, y) => x);
foreach (var sourceProperty in copyProperties)
{
var prop = destProperties.FirstOrDefault(x => x.Name == sourceProperty.Name);
prop.SetValue(destination, sourceProperty.GetValue(source));
}
}
}
I want to address a specific point in your question, regarding "forgetting some properties and disaster happens". The reason this happens is that you do not have a constructor on your model, you just have setters that can be set (or not) from anywhere. This is not a good approach for defensive coding.
I use constructors on all my Models like so:
public User(Person person, string email, string username, string password, bool isActive)
{
Person = person;
Email = email;
Username = username;
Password = password;
IsActive = isActive;
}
public Person Person { get; }
public string Email { get; }
public string Username { get; }
public string Password { get; }
public bool IsActive { get; }
As you can see I have no setters, so object construction must be done via constructor. If you try to create an object without all the required parameters the compiler will complain.
With this approach it becomes clear, that tools like AutoMapper don't make sense when going from ViewModel to Model, as Model construction using this pattern is no longer about simple mapping, its about constructing your object.
Also as your Models become more sophisticated you will find that they differ significantly from your ViewModels. ViewModels tend to be flat with simple properties like string, int, bool etc. Models on the other hand often include custom objects. You will notice in my example there is a Person object, but UserViewModel would use primitives instead like so:
public class UserViewModel
{
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsActive { get; set;}
}
So mapping from primitives to complex objects limits AutoMapper's usefulness.
My approach is always manual construction for the ViewModels to Model direction. In the other direction, Models to ViewModels, I often use a hybrid approach, I would manually map Person to FirstName, LastName, I'd but use a mapper for simple properties.
Edit: Based on the discussion below, AutoMapper is better at unflattering than I believed. Though I will refrain from recommending it one way or the other, if you do use it take advantage of features like Construction and Configuration Validation to help prevent silent failures.
Use Newtonsoft.Json to serialize viewmodel first and deserialize it to model.
First we need to Serialize the viewmodel:
var viewmodel = JsonConvert.SerializeObject(companyInfoViewModel);
Then Deserialize it to model:
var model = JsonConvert.DeserializeObject<CompanyInfo>(viewmodel);
Hence, all the data is passed from viewmodel to model easily.
One Line Code:
var company = JsonConvert.DeserializeObject<CompanyInfo>(JsonConvert.SerializeObject(companyInfoViewModel));
Okay, I've seen some similar questions to this, but the answers either confused me or seemed completely over-engineered, so I'd like to ask my own question.
I have a class called Tree, which has an object property from the class Plot, which has an object property from the class Year, which has an object property from the class Series, which has a string property called Id. This is summarized below.
public class Tree {
public virtual Plot Plot { get; set; }
// other properties...
}
public class Plot {
public virtual Year Year { get; set; }
// other properties...
}
public class Year {
public virtual Series Series { get; set; }
// other properties...
}
public class Series {
public virtual string Id { get; set; }
// other properties...
}
Each of these classes corresponds to the table of a database, and properties correspond to foreign key fields (for example, the Trees table has a field called PlotKey, which refers to a record in the Plots table). All I want to do is load all trees from the database whose corresponding Series have the Id "Adrian_2012" or "IPED Sample". I thought this would be a pretty easy taking using the following code:
IList<Tree> trees = session.CreateCriteria<Tree>()
.Add(Expression.Or(
Expression.Eq("Plot.Year.Series.Id", "Adrian_2012")
Expression.Eq("Plot.Year.Series.Id", "IPED Sample")
))
.List<Tree>();
But this is throwing: "NHibernate.Exceptions.GenericADOException : could not execute query". I have tried using Expression.Disjunction, I have tried using Aliases, Restrictions, and SimpleExpressions, and I know that nothing stupid like unmapped properties or misspelled criteria is occurring. The only other thing I've seen that might help is the ISession.QueryOver<>() function, but I get very confused by lambda expressions. Does anyone have a solution for me that would use just a simple CreateCriteria<> statement like that above?
Thanks in advance!
One not nice side of the Criteria queries is, that we have to define associations chain explicitly. I.e. we have to introduce JOIN:
15.4. Associations (cite:)
You may easily specify constraints upon related entities by navigating associations using CreateCriteria().
So to have a JOIN we need syntax like this
var trees = session
.CreateCriteria<Tree>()
.CreateCriteria("Plot", "p")
.CreateCriteria("Year", "y")
.CreateCriteria("Series", "s")
.Add(Expression.Or(
Expression.Eq("s.Id", "Adrian_2012")
Expression.Eq("s.Id", "IPED Sample")
))
.List<Tree>();
Also, check this:
NHibernate - CreateCriteria vs CreateAlias
So I am new to using AutoMapper and have been able to get basic mapping of items no problem with using LINQ statements that do not use the .Include("blah"), however when I have a statement for example like this;
var courses = dc.Courses.Include("Students")
.Include("CourseTimes")
.OrderBy(n=>n.CourseSemester.courseStart);
AutoMapper doesnt seem to pull any of the information from ("Students") or ("CourseTimes"). My objects are posted below and to give a quick breakdown, Courses contain a List of Students(I need Students so I can count the number of people in each course), Courses also contain a List of CourseTimes(so I can display the times of each class for the given course). Here is my ViewModel that I am using.
public class UserIndexCourseList
{
[Key]
public int courseId { get; set; }
public string courseCode { get; set; }
public string courseName { get; set; }
// this simply stored a count when I did Students.Count without using AutoMapper
public int size { get; set; }
public string room { get; set; }
public List<CourseTime> courseTimeSlot { get; set; }
}
Here are some of the AutoMapper statements I tried to used but had no luck with it working.
//to the viewmodel
Mapper.CreateMap<Models.Course, ViewModels.UserIndexCourseList>();
Mapper.CreateMap<Models.CourseTime, ViewModels.UserIndexCourseList>();
Mapper.CreateMap<Models.Student, ViewModels.UserIndexCourseList>();
//from the viewmodel
Mapper.CreateMap<ViewModels.UserIndexCourseList, Models.Course>();
Mapper.CreateMap<ViewModels.UserIndexCourseList, Models.CourseTime>();
Mapper.CreateMap<ViewModels.UserIndexCourseList, Models.Student>();
So essentially how can I create a Map which will also pull all of that information so I can use it with my ViewModel that was posted above ? I have tried numerous options but no luck.
I apologize for a similar post I made ahead of time but I don't think I explained myself well enough the first time. Thanks again!
By convention automapper maps properties with same names, so in your case you can do this:
public class UserIndexCourseList
{
...
//rename field so it has same name as reference
public List<CourseTime> CourseTimes{ get; set; }
}
or you can rename reference in EF so it's name is courseTimeslot.
Another solution if you don't want to rename your property is to add options to map, for example:
Mapper.CreateMap<Models.Course, ViewModels.UserIndexCourseList>()
.ForMember(d => d.courseTimeSlot,
opt => opt.MapFrom(src => src.CourseTime));
Edit: also they have great documentation, your case is described here: https://github.com/AutoMapper/AutoMapper/wiki/Projection
"Because the names of the destination properties do not exactly match up to the source property (CalendarEvent.Date would need to be CalendarEventForm.EventDate), we need to specify custom member mappings in our type map configuration..."
I am having some problem about how to work with an entity say an EF entity and a surrogate type, which will be bound to the UI.
Suppose that I have following classes
// Db Entity
public class Car
{
public virtual int Id { get; set; }
public string ChassisNumber { get; set; }
public virtual string Brand { get; set; }
public virtual string Name { get; set; }
}
// Surrogate type that reflects some properties of Car entity
// This class will be bound to UI
public class SurrogateCar
{
public string Brand { get; set; }
public string Name { get; set; }
}
Now I will be getting List<Car> from db and want to create a List<SurrogateCar> that represents my entities. I can do this easily in many ways, one of them like this:
List<Car> cars = CarTable.GetMyCars(); // Just a dummy method, suppose it returns all entities from Db.
List<SurrogateCar> surrogates = new List<SurrogateCar>();
foreach (var car in cars)
{
surrogates.Add(new SurrogateCar { Brand = car.Brand, Name = car.Name });
}
or I can write a custom cast method. But what I worry about is the performance. This method will be called frequently, so creating a list and populating it one by one seems a potential problem to me.
Do you have any better ways to do this, or is it okay to use it like this?
Thanks.
If you have a web service, and that service is always going to return the SurrogateCar class, then you can write your entity query to return the class you want rather than getting the class you don't want:
var cars = from c in context.Cars where {your condition}
select new SurrogateCar
{
Brand=c.Brand,
Name=c.Name
};
If, on the other hand you need the list of cars all the time, then as Roger pointed out AutoMapper is great! You just call
CreateMap<Car, SurrogateCar>
then you just use Automapper to populate your new list:
surrogates.AddRange(Map<IEnumberable<Car>, IEnumerable<SurrogateCar>>(cars));
Don't worry about the performance until you've really measured that's your bottleneck! Most probably these mappings between different types aren't that slow.
There are tools out there, eg AutoMapper
http://automapper.org/
It's main purpose isn't performance though, but to potentially makes you write easier and less code.
I believe what you are really looking for is AutoMapper, it allows for seamless, easy code written around this situation. I would not worry too much about the performance unless you need to worry about it.
Here is a SO about mapping lists using automapper, also