Entities to DTO - Entity framework - c#

Please review my code. For every my Entity i've created a service class, where i put all the access methods for this entity.This method are doing the transformation from the Entities to my DTO classes. This methods are called from the Web layer or a bussines method. Am I doing this righth? Or should I do it differently ?
The service method:
public static IEnumerable<OsobaDto> GetNakupyByOsoba(Guid guid)
{
using (FinanceEntities finance = new FinanceEntities())
{
var osoby = from o in finance.OsobaSet
where o.Nakupy.Any(n => n.idnakupu == guid)
select new OsobaDto
{
Id = o.idosoba,
Meno = o.meno,
Priezvisko = o.priezvisko,
Prijem = o.prijem,
Nakupy = o.Nakupy.Select(n => new NakupDto
{
IdNakupu = n.idnakupu,
Cena = n.cena,
Datum = n.datum
})
};
return osoby;
}
}
And the DTO class
public class NakupDto
{
public Guid? IdNakupu
{
get;
set;
}
public Decimal Cena
{
get;
set;
}
public DateTime Datum
{
get;
set;
}
public IEnumerable<OsobaDto> Osoby
{
get;
set;
}
public OsobaDto Platil
{
get;
set;
}

Everything is good, but I have one suggestion. If you have a lot of DTO objects you shoud think about writing a general converter. It can be done using reflection and explicit conversion operators.

Keep in mind the query wont actually hit the database until you actually use the IEnumerable you are are returning (because of deferred execution). I'm not sure how that will work since you are disposing the FinanceEntities before you actually execute the query. Assuming that works, it looks fine to me.

Related

ViewModel Object Convert to Entity Framework Object

Goal: to save ViewModel object by Entity Framework. I have UserViewModel object which has list of UnitViewModel. Then, I have a UserAdapter class which converts UserViewModel into Entity Framework User object (see Convert()below how).
Now, my question is how do I convert this list of UnitViewModel to its corresponding Entity Framework Unit list? - Do I have to get each object from DB Context by calling something like context.Units.Where(u=>myListofUnitIDs.Contains(u.UnitID))?
public class UserViewModel
{
public Guid? UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public DateTime? CreateTime { get; set; }
public List<UnitViewModel> UserUnits { get; set; }
}
public class UnitViewModel
{
public Guid UnitID { get; set; }
public string Name { get; set; }
public int? SortIndex { get; set; }
public DateTime CreateTime { get; set; }
public bool Assigned { get; set; }
}
public class UserAdapter
{
public static User Convert(UserViewModel userView)
{
User user;
if (userView.UserID.HasValue)
{
using (var provider = new CoinsDB.UsersProvider())
{
user = provider.GetUser(userView.UserID.Value);
}
}
else
{
user = new User();
}
user.FirstName = userView.FirstName;
user.LastName = user.LastName;
user.Password = StringHelper.GetSHA1(userView.Password);
user.UserName = user.UserName;
user.CreateTime = DateTime.Now;
// Problem here :)
// user.Units = userView.UserUnits;
return user;
}
}
UPDATE: The main concern here is that I have to retrieve each Unit from database to match (or map) it with ViewModel.Unit objects, right? Can I avoid it?
For your information, this operation is called as Mapping mainly. So, you want to map your view model object to the entity object.
For this, you can either use already existed 3rd party library as AutoMapper. It will map properties by reflection which have same name. Also you can add your custom logic with After method. But, this approach has some advantages and disadvantages. Being aware of these disadvantages could help you to decide whether you must use this API or not. So, I suggest you to read some articles about advantages and disadvantages of AutoMapper especially for converting entities to other models. One of such disadvantages is that it can be problem to change the name of one property in the view model in the future, and AutoMapper will not handle this anymore and you won't get any warning about this.
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit = Mapper.Map<UnitViewModel, UserUnit>(item);
user.Units.Add(userUnit);
}
So, I recommend to write your custom mappers.
For example, I have created a custom library for this and it maps objects lik this:
user.Units = userView.UserUnits
.Select(userUnitViewModel => userUnitViewModel.MapTo<UserUnit>())
.ToList();
And I am implementing these mapping functions as:
public class UserUnitMapper:
IMapToNew<UnitViewModel, UserUnit>
{
public UnitViewModel Map(UserUnit source)
{
return new UnitViewModel
{
Name = source.Name,
...
};
}
}
And then in runtime, I am detecting the types of the objects which will be used during mapping, and then call the Map method. In this way, your mappers will be seperated from your action methods. But, if you want it urgently, of course you can use this:
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit= new UserUnit()
{
Name = item.Name,
...
};
user.Units.Add(userUnit);
}

How to return specific set of data from a class

I have a similar structure to the one below
Base class
public class BaseClass
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Guid Guid { get; set; }
public string Hometown { get; set; }
}
Derived Class
public class DerivedClass : BaseClass
{
public List<DerivedClassDataItem> Data { get; set; }
}
Data class
public class DerivedClassDataItem
{
public string Datum1 { get; set; }
public string Datum2 { get; set; }
public string Datum3 { get; set; }
public string Datum4 { get; set; }
public int Datum5 { get; set; }
public DateTime Datum6 { get; set; }
}
What is the best practice to return specific set of info from the DerivedClass?
a potential set could be:
Name, Address, Guid and then a Data list that only contains Datum1 and Datum4
I could see anonymousTypes, Tuples or another set of class(es), all to be valid approaches.
My concern about creating new set of classs for the set returned is that the class(s) structure will be similar to the structure of the three mentioned above except it will have fewer selected members, which to me, does not sound ideal. (duplicate code and structure)
Using anonymousTypes was my initial solution to tackle this, something like
List<DerivedClass> list = new List<DerivedClass>();
var mySet = list.Select(d => new
{
Name = d.Name,
Address = d.Address,
.
.
.
.
.
Data = d.Data.Select(item => new
{
Datum1 = item.Datum1,
Datum4 = item.Datum4
})
});
but again, that was a headache for us to track through httpResponse and through out API calls.
Should I go with Tuple?
Any insights as to what is the best practice for doing this?
Edit
I am using this set of data to be a response returned by a API/GET call. I will send the set back using HttpRespose and then the framework will transform that into json
this is an actual method we have now
private void populateReturnFile()
{
var returnFileAnonymous = new
{
Vendor = this.Vendor,
OrganizationName = this.OrganizationName,
User = this.User,
Platform = this.Platform,
DictionaryType = this.DictionaryType,
UseCaseId = this.UseCaseId,
Data = this.Data.Select(d => new
{
MigrationTermId = d.MigrationTermId,
ImoLexicalCode = d.ImoLexicalCode
})
};
this.returnFile = returnFileAnonymous;
}
Then my GET will return the retunFile (this is a very simple method, i have remove irrelevant code)
[HttpGet]
public HttpResponseMessage Get(Guid migrationFileId)
{
ProblemList problemList = ProblemList.GetProblemList(migrationFileId);
return Request.CreateResponse(HttpStatusCode.OK, problemList.ReturnFile, new JsonMediaTypeFormatter());
}
If API calls is where you are using these classes, then I personally like to keep it simple and avoid complex inheritance hierarchy. Remember, simple code is good code.
I would make a separate class for each api request/response call. For very simple api calls (ajax requests for example) I like to use anonymous types, but for controllers that only handle API calls I like to create separate classes, organized in a nice folder structure.
Everyone has their "style" but as long as you strive for simplicity your code will be maintainable.

Automapper not populating destination from source

I have a simple test solution which consists of two projects (a 'business' layer and a Data Access layer) using Catel to tie the two together - works fine, no problems.
However, have been reading about how useful AutoMapper can be for helping to move data around such a setup by allowing easy population of DTO's and decided to give it a look...that's when my problems started!
I'm using Entity Framework 6.1, VS 2013 Express for Desktop and accessing a SQL Server Express 14 db - no problems with data retrieval and data displays correctly in my views.
AutoMapper was added using NuGet.
In order to use AutoMapper I've set up the following in my App.xaml.cs
private void InitializeAutomapper()
{
Mapper.CreateMap<Result, ResultDto>();
Mapper.AssertConfigurationIsValid();
}
This code is the first item called inside my 'OnStartup'.
A service in my business layer makes a call to the Data Access layer and retrieves a list of Result entites.
Subsequently, I take a single entity from this list and use that in the AutoMapper mapping call.
I'm trying to populate a resultDTO from this single entity, using the following
Result res = ResultList.First();
ResultDto resultDTO = Mapper.Map<Result, ResultDto>(res);
'res' is correctly populated with data but resultDTO is filled with the default values for the individual data types (in = 0, string = null, DateTime = {01/01/0001 00:00:00}) ie; no values are mapped from the source to the destination.
There are References in both projects to AutoMapper and AutoMapper.Net and no errors are raised - it just doesn't work as advertised...
I'm not slagging off the software, just asking what I'm doing wrong!
I realise there isn't much code to work on here but, in truth, what is posted here is pretty much all I've added to try out AutoMapper. I can see, conceptually how useful it could be - I just need to figure out how to make it happen so any help/comments gratefully received...:)
EDIT
#Andrew, as requested -
Result Class:
public partial class Result
{
public int Div { get; set; }
public System.DateTime Date { get; set; }
public string HomeTeam { get; set; }
public string AwayTeam { get; set; }
public int FTHG { get; set; }
public int FTAG { get; set; }
public string FTR { get; set; }
}
ResultDTO Class:
public class ResultDto
{
int Div { get; set; }
DateTime Date { get; set; }
string HomeTeam { get; set; }
string AwayTeam { get; set; }
int FTHG { get; set; }
int FTAG { get; set; }
string FTR { get; set; }
// Added tonight to try and get it to work
public ResultDto()
{
Div = 0;
Date = DateTime.Now;
HomeTeam = null;
AwayTeam = null;
FTHG = 0;
FTAG = 0;
FTR = null;
}
}
#stuartd, the following is used to retrieve the ResultList from which Result is obtained:
// Produce a list of DataLayer.Result entities.
var ResultList = (from x in dbContext.Results.Local
where x.HomeTeam == team.TeamName.ToString() || x.AwayTeam == team.TeamName.ToString()
orderby x.Date
select x).ToList();
Please note 'team.Teamname' is passed into the above from an external source - seems to be working fine.
So to sum up -
I produce ResultList as a list of Result entities.
Fill Result with the first entity in the list.
Try to map this Result entity to ResultDTO
Fail :(
Hope this helps!
By default, class members are declared private unless otherwise specified so the ResultDto properties aren't visible outside of the class.
public class ResultDto
{
int Div { get; set; }
....
}
needs to be
public class ResultDto
{
public int Div { get; set; }
....
}
AutoMapper can work out the type you are mapping from from the arguments provided. Try this:
ResultDto resultDTO = Mapper.Map<ResultDto>(res);
UPDATE
This is wrong, or at least won't help. We need to see the source and destination classes as mentioned in the comments.

avoid redundant conditional statements

Using the following code, assume I have 5 different types that I might receive in the variable type. Instead of writing 5 conditional statements, is there a way to write one and use the variable "type" to dictate what the model is, in this case "CommentVote?" Or is this more a deficiency in the way I've designed the data model with each of those 5 things having a "vote" model?
if (type == "comment")
{
CommentVote voteObj = db.CommentVotes
.Where(x => x.UserID == UserID && x.CommentID == id)
.SingleOrDefault();
if (voteObj != null)
{
voteObj.Vote = vote;
db.SaveChanges();
}
else
{
CommentVote c = new CommentVote {
CommentID = id, UserID = UserID, Vote = vote, DateCreated = DateTime.Now
};
db.CommentVotes.Add(c);
db.SaveChanges();
}
count = (db.CommentVotes.Count(x => x.CommentID == id && x.Vote == true) - db.CommentVotes.Count(x => x.CommentID == id && x.Vote == false));
}
Magic Code: The stuff I would love to be able to do.
var modelName = "";
var modelOtherName = "";
if (type == "comment") {
modelName = CommentVote;
modelOtherName = CommentVotes;
}
modelName voteObj = db.modelOtherName
.Where(x => x.UserID == UserID && x.CommentID == id)
.SingleOrDefault();
Update: I'm beginning to think my model may be crap based on some of the reading referenced bellow. So I am including some of that as a reference. Let me know if that's the problem I should be trying to solve.
public class CommentVote
{
public int CommentVoteID { get; set; }
public bool Vote { get; set; }
public DateTime DateCreated { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public int CommentID { get; set; } //This row changes from model to model
public virtual Comment Comment { get; set; } //This row changes from model to model
}
I have a handful of models that are almost identical.
As I understand you question, it more database architecture-related.
If those kind of votes are not very different from each other (in terms of properties) I woldn't use different tables for them. Instead create one Vote table with Type column and (as in the example you provided) nullable column for CommentID.
Then you can use class inheritance to reflect your votes (Vote base class and CommentedVote child class).
Table Per Hierarchy Inheritance in Entity Framework
Update:
Best is not to repeat the same propertieses in all classes. You just use inharitence like this:
public abstract class Vote
{
public int VoteID { get; set; }
public bool isVote { get; set; }
public DateTime DateCreated { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public int VoteType { get; set;} //this property specifies type of vote (e.g. VoteType=1 for CommentedVote )
}
public class CommentVote : Vote
{
public int CommentID { get; set; }
public virtual Comment Comment { get; set; }
}
public class OtherVote : Vote
{
public int OtherID { get; set; }
public virtual Other Other { get; set; }
}
In this very good blog post you can find all possible approches. The one I'm writing about is called Table per Hierarchy (TPH).
You can absolutely reduce the code to a single statement assuming that you perform the same actions and set the same data. In this case, you should have an interface that contains the common actions and data and an object factory to instantiate the correct object based on the type.
You could do it if you implement the Factory pattern with reflection, a very basic example is shown here.
In a nutshell what you do is this: Since you have 5 different types that it could be, you would make 5 different classes that each implement a specific interface. You then create the factory class to use reflection to grab the class that is the most appropriate for your situation (be it with a straight-up class name, like in the example, or with an Attribute over the class, such as here). The factory returns an instance of that interface, which you would then just invoke the exposed method from the interface to do all of this for you.
The best part of this is that if you ever need to make another type, all you'd have to do is add another class with that attribute/name that you would be searching for in the factory. None of your other code would need to be affected, thus making you compliant with the Open/Closed Principle.

Entity Framework (5.0) Code First - Insert into Collection within Collection

I've got three classes.
Event > Workshop > Workshop Times
I'm currently looking for best way of inserting records into the Workshop Times, this is running through code first using ICollections.
Looking for something along the lines of this, but I know it doesn't work:
//Create connection
var db = new Context();
var Event = db.Events
.Include("Workshops")
.Include("Workshops.Times")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Event.Workshops.Add(new Workshop
{
Name = tbWorkshopName.Text,
Description = tbWorkshopDescription.Text,
Times.Add(new WorkshopTime{
//Information for times
})
});
db.SaveChanges();
Chopped down classes:
public class Workshops{
public int id { get; set; }
public string name { get; set; }
public ICollection<WorkshopTimes> Times{get;set;}
}
public class Events {
public int id { get; set; }
public string name { get; set; }
public ICollection<Workshops> WorkShops { get; set; }
}
public class WorkshopTimes {
public int id { get; set; }
public DateTime time { get; set; }
}
You are definitely on the right track with your query, however your include statements appear incorrect. From your model I would expect:
var Event = db.Events
.Include("WorkShops")
.Include("WorkShops.events")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Note this uses the property names not the types. This will ensure that the entities in the listed nav properties will be included in the result.
In addition you can use a lambda to do the same thing (but its typesafe)
Check out here for how to do a very similar scenario to yours:
EF Code First - Include(x => x.Properties.Entity) a 1 : Many association
or from rowan miller (from EF team)
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
And make sure you are using System.Data.Entities for lambda based includes ( Where did the overload of DbQuery.Include() go that takes a lambda? )

Categories