A while back, I fell into the fat controller trap when I was first working with MVC. My first app used EF4 to make all the models I needed. I just put all my logic into my controller actions. While it worked, it's definitely not the best practice way. To do it the right way I started trying to build my models based on my EF objects in an effort to follow the skinny controller concept.
I've run into a roadblock in trying to find the best way to populate my models. Is there a way to run a LINQ query and have it populate your model without having to iterate through the properties to set to another class?
Something like this:
// from EF model built from database
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
public class MyObjectModel : MyEFObject
{
private Entities _data = new Entities();
public MyObjectModel(int? id)
{
if(id.HasValue) // get an existing record
{
this = _data.MyEFObjects.Where(m => m.ID.Equals(id)).Single();
// or populate right out of the query
_data.MyEFObjects.Where(m => m.ID.Equals(id))
.Select(o => new {
this.ID = o.ID,
this.Name = o.Name,
this.Title = o.Title
});
}
else
{
// set defaults for a new MyObjectModel
}
}
public void Save()
{
// takes the current object and saves changes
}
}
I know you can add a function to the EF Entity object, but I like having the option to Create or Update all tied up in one call (Save method). I don't see the point messing with a model if I have to essentially recreate what I already have from my EF Object. If I simply have a method on a class that accepts a populated object, the concept of a usable model for my views is negated.
What you could do is have a domain model, ef model and and adapter . I think this keeps the code pretty clean and nicely separates the mapping logic.
//Domain model to decouple from EF
public class MyObjectModel
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Auto generated Entity Framework class
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Adapter responsible for mapping your data to your domain model
public class MyObjectModelAdapter : MyEFObject
{
public MyObjectModelAdapter(MyEFObject entity)
{
if(entity != null)
{
this.ID = entity.ID;
this.Name = entity.Name;
this.Title = entity.Title;
}
else
{
// set defaults for a new MyObjectModel
}
}
}
Then the basic usage would be:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x));
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)));
If you specifically require a list of MyObjectModel then you could do the following:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x) as MyObjectModel);
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)) as MyObjectModel;
Of course you don't want to chain your entity context together like that, it is just to show usage.
Slauma is right. LINQ to Entities won't accept it. I tried a couple of versions of what was posted and I only found my self with a kludgy mess. I got it to the point where I could set instance values, but by then EF wouldn't register a change had been made and defeating the whole purpose. There may be a way to do this, but as of now, the steps to make it work seem to be overkill.
I ended up with something like this:
public class MyObjectModel : MyEFObject
{
public void Save(int? id, MyObjectModel model)
{
var data = new Entities();
MyEFObject foo;
if(id.HasValue)
{
foo = data.MyEFObjects.Where(e => e.ID.Equals(id.Value)).Single();
}
else
{
foo = new MyEFObject();
}
foo.Name = model.Name;
foo.Title = model.Title;
if(!id.HasValue)
{
data.MyEFObjects.AddObject(foo);
}
data.SaveChanges();
}
}
I didn't want to have to work with two instances of my model, but it works and I have my lean controller action.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.