I have an empty sql table which contains around 100 column headers (fields), using database first approach I have created a single class with all the 100 fields as properties. Now I want to select only 10 fields out of all the properties and insert some data to those fields, such that the existing table should have the inserted data for only those 10 columns and the remaining columns should be updated with NULL. For instance,
public class Product
{
public int UniqueID {get; set;}
public string ProductName {get; set;}
public string type {get; set;}
etc......
}
Now I want the table should be updated with only UniqueID and ProductName and all the remaining fields should have NULL.
I am thinking of using Dictionary<string,object>, to add all the selected properties to dictionary and pass it to the database table.
Please share some ideas on how to implement this scenario using Entity Framework.
If it is MVC and you want to add/edit a subset use a view model:
// this is a viewmodel intended for a particular view, for example AddProductSubset.chtml
public class AddProductSubsetViewModel
{
public int UniqueID {get; set;}
public string ProductName {get; set;}
// add other properties you will be updating from the entity model
// you can also add properties from other entities or things only needed by the view
}
[HttpGet]
public ActionResult AddProductSubset(AddProductSubsetViewModel vm)
{
var vm = new AddProductSubsetViewModel();
// fill in any default values before add/edit
return View(vm);
}
[HttpPost]
public ActionResult AddProductSubset(AddProductSubsetViewModel vm)
{
if (ModelState.IsValid)
{
// map your viewmodel to the entity model. See automapper.
var product = new Product
{
UniqueID = vm.UniqueID, // unless this is identity, then omit
ProductName = vm.ProductName,
otherfield = vm.otherfield,
...
// unmapped entity fields will be set to their default (null, etc)
}
context.Products.Add(product);
context.SaveChanges();
return RedirectToAction("Index")
}
return View(vm);
}
You can reflect and hydrate properties to an instance, then add I think. This should do it
public void ReflectIntoModel<T>(Dictionary<string, object> dic)
{
T m = (T)Activator.CreateInstance(typeof(T));
var prop = typeof(T).GetProperties();
foreach (var a in prop)
{
dynamic val;
if (dic.TryGetValue(a.Name, out val))
a.SetValue(m, val);
}
}
Just make sure you're careful with typing the value, and the fact that the field names are case sensitive
Related
In my DTO classes, I have some properties wiyth simple getter/setter (get; set;) while some of the properties have more complex getters/setters (like evaluating the value by some other property/variable etc)
[Serializable]
public class MyClassDto
{
public virtual string Name { get; set; }
public virtual string Description { get { return Name; } set { Name = value; } }
....
}
In above example, I want to get property Name, but do not want to get Description
I am trying to use PropertyInfo to find properties which have get;set; as getter/setter but failed to do so.
My reason for a such development is; properties with simple get;set; have a property with the same name in my Entity classes, alongside with a column in the database table. My Entities also have some properties which do not have a related column on the database table. So getting the properties with simple getters/setters will give me the properties with related database columns.
Meanwhile, I am using NHibernate.
check if this meets your requirment.
var property = typeof(MyClassDto).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(t => t.CanRead && t.CanWrite);
foreach (var item in property)
{
string propertyName = item.Name;
bool CompilerGenerated = item.GetGetMethod()
.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any();
//Description is not CompilerGeneratedAttribute so return false;
}
I have an entity "Rep"...
public partial class rep
{
public string repid { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Title { get; set; }
public string Department { get; set; }
many, many more properties...
}
I then have a form that updates only the rep's first and last name. When the form is submitted, the first and last name are updated, but every other property is set to null.
I want the other properties to be left alone so they retain there existing values.
I could include all of the properties of the entity with hidden form fields to pass their values along to the Edit method, but is there a better/easier way?
I'm familiar with setting the IsModified property...
entry.Property(e => e.Title).IsModified = true;
But that seems unnecessary as well. Is this the way to go, or is there a better way?
The code you use to render the view and update the entity are quite relevant but missing, but I can guess what they look like:
#model ...rep
#using (Html.BeginForm()) {
#Html.HiddenFor(m => m.repid )
#Html.TextBoxFor(m => m.FirstName )
#Html.TextBoxFor(m => m.LastName)
<input type="submit" />
}
And in your controller:
[HttpPost]
public ActionResult Update(rep model)
{
using (var context = new MyContext())
{
context.reps.Attach(model);
context.SaveChanges();
}
return RTA(...);
}
This is attaching the entity that was posted, which is an entirely new object that is unknown to the context and its change tracker. By attaching an entity like that, you tell the context this is the new representation you want saved, i.e. with most properties set to null.
You can easily fix this by first retrieving the entity and then updating only the required properties:
[HttpPost]
public ActionResult Update(rep model)
{
using (var context = new MyContext())
{
var entity = context.reps.Find(rep.repid);
entity.FirstName = model.FirstName;
entity.LastName = model.LastName;
context.SaveChanges();
}
return RTA(...);
}
But don't do this. See What is ViewModel in MVC? or ViewModel Best Practices or search the web or this site on "mvc viewmodel".
Mainly because your database entity contains columns you don't want displayed or updated (mass assignment) and because sooner or later you will want to use extra properties in your view (dropdown data, script variables, related entities) that you can't stick in your database entities.
Genarally you can say: don't use entity models for view models, especially not when they are posted back. So the viewmodel is the way to go:
public class RepresentativeViewModel
{
public string RepID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You then only have to alter your view's model declaration:
#model ...RepresentativeViewModel
And your controller just looks like the easiest solution:
[HttpPost]
public ActionResult Update(RepresentativeViewModel model)
{
using (var context = new MyContext())
{
var entity = context.reps.Find(rep.RepID);
entity.FirstName = model.FirstName;
entity.LastName = model.LastName;
context.SaveChanges();
}
return RTA(...);
}
You can of course replace the entity.FirstName = model.FirstName; mapping code into some automated solution, for example using AutoMapper.
You either use the IsModified property like you mentioned or you can create a view model that has the properties you want to change and use a mapper, like AutoMapper, to copy the values from the input to the entity. Typically I have a base class that has my modifiable data and a subclass that has the relationships and data I don't want to change like CreatedBy and stuff. Hidden fields is defnitely NOT the way to go.
You have two methods you could try
Create a view model with only the properties you want to update.
Store the values I the other properties in hidden fields they will not be returned null
I've got an object that has a property which, on creation, should always be populated with the object's id(primary key).
How do I do that?
I've tried assigning the id to the field just after the db savechanges(), before returning to the view, but that creates two records on my db.
Also tried loading a new instance of the same, assign the id to the field and save it, but also creates two records.
Thanks for any help.
//model
public partial class supplier
{
public int id { get; set; }
public int ref { get; set; }
}
//controller
public ActionResult Create(supplier sup)
{
if (ModelState.IsValid)
{
db.suppliers.add(sup)
db.SaveChanges();
sup.ref = sup.id;
db.SaveChanges();
}
...
}
Hi all, thanks for all your help... I've found a solution... don't really know if it's the correct one, but it does the job.
For whoever is interested here it is:
supplier needToUpdateSupplier = (from s in db.suppliers where s.id.Equals(supplier.id) select s).ToList().FirstOrDefault();
if (needToUpdateSupplier != null)
{
needToUpdateSupplier.ref = supplier.id;
db.suppliers.Attach(needToUpdateSupplier);
db.Entry(needToUpdateSupplier).Property(e => e.ref).IsModified = true;
db.SaveChanges();
}
Create the object
Save it (SaveChanges). This will give you the id.
Assign the id to your property, using the existing object (you don't need to load it again)
Save again
Notes: The property must be nullable, because up on creation it will be empty.
// A Test object
class MyObject
{
public int ID {set;get;}
public int? MyProperty {set;get;}
}
void Foo()
{
var test = new MyObject();
db.MyObjects.Add(test);
db.SaveChanges();
// at this moment test has the Id set. You can assign it.
test.MyProperty = test.Id;
db.SaveChanges();
}
With EF it should set the ID for you:
db.Posts.Add(post);
db.SaveChanges();
// post.ID should be now set
How to fetch data with EF on one to many relationship.i.e if i have a table name Person(personID as primary key) and another table name streetLivedIn(personID as foreign key).
Now i force my controller method to pass an object of type person
var persons=db.persons();
return View(persons);
Now i want to display Person details along with street(i.e that what stored at streetLivedInTable) he/she lived at.suppose i have an Entityset of person
public class Persons
{
public string Name{get;set;}
//NAVIGATIONL PROP.
public virtual ICollection<streetLivedIn>{get;set}
}
Suppose the navigational property name is Streets.
public class Persons
{
public string Name { get; set; }
//NAVIGATIONL PROP.
public virtual ICollection<streetLivedIn> Streets { get; set }
}
Then you can use the Include method to eager load this property.
var persons = db.persons.Include("Streets");
return View(persons);
You can display this in various ways. Eg
#foreach (var person in Model)
{
<div>#person.Name</div>
#foreach (var street in person.Streets)
{
<div>#street.Name</div>
}
}
Or you can use the WebGrid, MvcContrib Grid, etc
Assuming you don't want to expose the Entity Framework data model directly to the view, and instead do a conversion to business objects you create, I would simply iterate the EF datamodel with a double foreach loop. Entity Framework creates the one-to-many-references for you using containment - why not take advantage of that.
I prefix the EF-generated classses with "Ef" for clarity.
var personList = new List<Person>();
foreach (var efPerson in EfPersons)
{
var person = new Person
{
Name = efPerson.Name,
StreetsLivedIn = new List<StreetLivedIn>();
}
foreach (var efStreet in efPerson.EfStreetsLivedIn)
{
var street = new StreetLivedIn { Name = efStreet.Name; }
person.StreetsLivedIn.Add(street);
}
personList.Add(person);
}
return View(personList);
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.
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.
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.