AutoMapper - Why it is overwriting whole object? [duplicate] - c#

This question already has answers here:
Automapper: Update property values without creating a new object
(4 answers)
Closed 4 years ago.
I don't understand why it's overwriting my whole object. The reason is that I get my User object from db an I want to assign new values from DTO. Instead of just adding those new values it's creating new object that has new values but all previous are set to null.
How can I make sure that in this case he will "upgrade" my object, not create new one?
Scenario
/users/{id} - PUT
// User has id, username, fullname
// UserPut has fullname
public HttpResponseMessage Put(int id, UserPut userPut)
{
var user = _db.Users.SingleOrDefault(x => x.Id == id); // filled with properties
Mapper.CreateMap<UserPut, User>();
user = Mapper.Map<User>(userPut); // now it has only "fullname", everything else set to null
// I can't save it to db because everything is set to null except "fullname"
return Request.CreateResponse(HttpStatusCode.OK, user);
}

The Mapper.Map has an overload which takes a source and a destination object. In this case Automapper will use the given destination object and does not create a new object.
So you need to rewrite your Mapper.Map to:
Mapper.Map<UserPut, User>(userPut, user);

Related

how can i write more simple code without new select? [duplicate]

This question already has answers here:
Delete entities without loading them into memory
(5 answers)
Closed 2 years ago.
public async Task DeleteAsync(int id)
{
Food food = await dataContext.Foods.FindAsync(id);
dataContext.Foods.Remove(food);
await dataContext.SaveChangesAsync();
}
it is CRUD operation for food model. I want to do it without new select.
Remove needs an object to remove. So if you want to use Remove, you have to select (or create an object and set the ID as in the answer of Максим Кошевой) the object in your case.
If you want to remove directly, you can type the query like this :
dataContext.Database.ExecuteSqlCommand("DELETE FROM Foods WHERE ID = {0}", id);
//Assuming the ID field's named ID in your Foods table and the table is named Foods (in some cases EF can add s at the end of tables).
You don't actually need all the fields to delete a record. You only need id. So you can create a simple stub that would only contain id and pass it into Remove method.
public async Task DeleteAsync(int id)
{
var food = new Food { Id = id };
dataContext.Foods.Remove(food);
await dataContext.SaveChangesAsync();
}
You can find more information about it here: https://www.learnentityframeworkcore.com/dbcontext/deleting-data

How to check whether model have some changes in C# MVC

I have appSourceInfoModel taken from Database, now i am passing ViewModel i.e. reviewerAppsBacklogViewModel and if reviewerAppsBacklogViewModel and appSourceInfoModel are same then do not update database if there are changes then Update. I am doing, first assigning to variable var DBappSourceInfoModel = appSourceInfoModel; then I assigning some values to appSourceInfoModel then comparing the initially saved model DBappSourceInfoModel and appSourceInfoModel. But, assigning some values to appSourceInfoModel also change values in the initially saved model DBappSourceInfoModel. All of the code can be found below.
AppSourceInfo appSourceInfoModel = _appSourceInfoRepository.Get(a => a.Review.ReviewId == reviewId);
var DBappSourceInfoModel = appSourceInfoModel; //Initially save Model in var
appSourceInfoModel.Cost = reviewerAppsBacklogViewModel.Cost;
appSourceInfoModel.InProgress = true;
appSourceInfoModel.PegiRating = reviewerAppsBacklogViewModel.PegiRating;
appSourceInfoModel.Rating = reviewerAppsBacklogViewModel.AverageUserReviewsRating;
appSourceInfoModel.DownloadCounter = reviewerAppsBacklogViewModel.NoofDownloadsFromSource;
appSourceInfoModel.ReviewCounter = reviewerAppsBacklogViewModel.NoofReviewOfSource;
appSourceInfoModel.StoreCategory = reviewerAppsBacklogViewModel.StoreCategory;
var IsAppSourceInfoModelChanged = !DBappSourceInfoModel.Equals(appSourceInfoModel);
if (IsAppSourceInfoModelChanged)
{
_appSourceInfoRepository.Update(appSourceInfoModel);
}
I have Solved it using this simple Code in My Model i.e. AppSourceInfo
public object Clone()
{
return this.MemberwiseClone();
}
and change the following code
var DBappSourceInfoModel = appSourceInfoModel; //Initially save Model in var
to
var DBappSourceInfoModel = (AppSourceInfo) appSourceInfoModel.Clone();
You need to perform a Copy (shallow probably sufficient)
var DBappSourceInfoModel = appSourceInfoModel;
Is simply creating a reference to the same object. Implement ICloneable on the DBappSourceInfoModel then use Clone method,
Your Clone method needs to copy all the info to the new Object, also performing Deep Copies on internal references if needed,
This will copy all the details to the other object and create two separate objects,
look here for reference:
https://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx
EDIT
Just to be clear, you also need to use the IComparable interface to define how the objects are compared for equality,
https://msdn.microsoft.com/en-us/library/system.icomparable%28v=vs.110%29.aspx

Dynamic table name in linq [duplicate]

This question already has answers here:
Querying data using Entity Framework from dynamically created table
(2 answers)
Dynamically set the table name in LINQ query
(3 answers)
Closed 8 years ago.
I'm trying to execute some LINQ commands using a dynamic table name. For example, instead of:
var o = (from x in context.users select x);
I want to use something like:
var o = (from x in getTableObjectByName("users", context) select x);
More or less. Here's the code I have so far, which both compiles and runs:
using (MySiteEntities ipe2 = new MySiteEntities()) {
var propinfo1 = Type.GetType("MySiteNamespace.MySiteEntities").GetProperty("users");
var propval1 = propinfo1.GetValue(ipe2, null);
}
That runs, but always returns zero records. The users table most definitely contains records, and in any case when I call it directly using the first method above I get all of the records as expected. How can I modify my code to actually pull down records, rather than just an empty collection?
Edit: I've also tried this:
using (MySiteEntities ipe = new MySiteEntities())
{
var prop = Type.GetType("MySiteNamespace.MySiteEntities").GetProperty("users");
Type dbsetType = typeof(DbSet<>);
dbsetType = dbsetType.MakeGenericType(Type.GetType("MySiteNamespace.user"));
Type t = dbsetType.GetType();
var val = prop.GetValue(ipe, null);
}
In this case, the code not only runs, but actually returns the results as expected. However, val is an Object. I need to cast it to the type DbSet<user>, which would be easy enough, except that the parameter user is only known at runtime....the cast needs to be dynamic as well. I've tried using Convert.ChangeType(val, t);, but that throws an
InvalidCastException (Object must implement IConvertible).
How can I convert the val variable to an actually usable object?
No idea if this is relevant, but this is on EntityFramework 4.
In your DbContext class, add a method say called Set that returns:
public DbSet Set(string name)
{
// you may need to fill in the namespace of your context
return base.Set(Type.GetType(name));
}
Which you can query like this:
using (var db = new YourDataContext())
{
// Since your DbSet isn't generic, you can can't use this:
// db.Set("Namespace.EntityName").AsQueryable().Where(a=> a.HasSomeValue...
// Your queries should also be string based.
// Use the System.Linq.Dynamic nuget package/namespace
var results = db.Set("Namespace.EntityName")
.AsQueryable()
.Where("SomeProperty > #1 and SomeThing < #2", aValue, anotherValue);
// you can now iterate over the results collection of objects
}
More information on System.Linq.Dynamic can be found here

IDictonary<string,object> object has multiple objects, how to seperate?

I'm currently about to develop a website with asp.net mvc4 and mongodb as database. As the Microsoft Membership Provider does only support SQL-DB's, I've to use another Membership Provider. I decided to use the ExtendedMongoMembership Provider. Everything worked as long as I had no additional user properties passed during the Account creation. As I tried to add some additional properties like e-mail, the functionality of the CreateUserRow function throws and exception. I've downloaded the source and try to fix it. Therefore I have to separate objects inside of objects, that seems to be the way how the necessary data is passed into the function.
public bool CreateUserRow(string userName, IDictionary<string, object> values)
{
string userTableName = "Users";
List<BsonElement> elements = new List<BsonElement>();
elements.Add(new BsonElement("UserName", userName));
elements.Add(new BsonElement("_id", GetNextSequence("user_id")));
if (values != null)
{
// Here I'm facing the problem where I have to get the property names
// and the values to add them to the elements list
// The IDictionary is unfortunately not build in the way
// propertyname,value so that I could get the entries in an easy way
}
var collection = _provider.GetCollection(userTableName);
var result = collection.Insert(new BsonDocument(elements.ToArray()));
return result.LastErrorMessage == null;
}
The IDictonary contains 4 keys named (Comparer,Count,Keys,Values), the key names and their count is fixed. The property name(s) for write to the db are stored as single objects inside of an object that is the value with the key "Keys" inside the Dictonary. The same applies to the values for the db, these are stored also inside an object that is an value with the key "Values". My problem is that I have no idea how to separate these objects. Here is an picture that shows the structure of the dictionary during the debug session.
http://i.stack.imgur.com/h4z7I.jpg
How I can access the objects inside of the objects that are stored as values?
EDIT:
Found now a way, is there a better one ?
var propnames = ((IEnumerable<object>) values["Keys"]).ToArray();
var propvalues = ((IEnumerable<object>)values["Values"]).ToArray();
dynamic test;
for (int i = 0; i < propnames.Count(); i++)
{
Type type = propvalues[i].GetType();
test = Convert.ChangeType(propvalues[i], type.UnderlyingSystemType);
//BsonValue bsonValue = test as BsonValue;
elements.Add(new BsonElement(propnames[i] as string,test ));
}

Insert new object with existing object

I am new to EF 4 and this is what I have done so far:
Create an edmx file based on my database
Create a code generation for my objects (POCO). Now I have a model1.tt, when expanded I see al my classes
Create a repository for each class, based on IRepository
Now, I am working with two objects, A and B. Object A has a property of type B. In my winform I have a combo filled with objects of type B. When the save button is pressed, a new instance of class A is created and all the properties are set. The object B property is set as follows:
objectA.myObjectB = (objectB)cmbBObjects.selectedItem;
Then I create a repository for objectA and call the save method. In this save method I have this code±
public bool Save(ObjectA obj)
{
using(MyContext context = new MyContext())
{
context.objectAs.AddObject(obj);
context.SaveChanges();
}
}
This code, does save a new entry to the database, but it is also creating a new record for object B! I don't want this, because object B already exists in the database! (I have selected this one from the combobox).
This is how I fill my combobox:
In the objectB repository:
public IList<ObjectB> GetAll()
{
using(MyContext context = new MyContext())
{
IList<ObjectB> objects = context.objectBs.ToList();
return objects;
}
}
In my form:
ObjectBRepository rep = new ObjectBRepository();
IList<ObjectB> objects = rep.GetAll;
cmbBObjects.Datasource = objects;
// etc..
So my question is, what do I have to do to save object A without creating a new record for objectB?
If you don't want insert objectB you must inform EF about it. When you call context.objectAs.AddObject(obj) for objectA you are saying: I want to insert objectA and all its dependencies. But obviously you don't want to save dependecies so you must either:
Load objectB from DB before adding it to objectA. In such case EF will know that objectB is existing object and it will not insert it again.
Attach objectB to context before adding it to objectA. ObjectB will be handled as existing but unchanged.
Set the state of objectB after inserting objectA. You can do that by calling: context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged)
Example of the fist suggestion:
var id = objectB.Id;
objectA.myObjectB = context.ObjectBs.SingleOrDefault(o => o.Id == id);
Example of the second suggestion:
context.ObjectBs.Attach(objectB);
objectA.myObjectB = objectB;
Example of the third suggestion:
objectA.myObjectB = objectB;
context.ObjectAs.AddObject(objectA);
context.ObjectStateManager.ChangeObjectState(objectB, EntityState.Unchanged);
I suppose that problem in following row:
objectA.myObjectB = (objectB)cmbBObjects.selectedItem;
Because of result (objectB)cmbBObjects.selectedItem detached from datacontext entity framework create new instance. Instead this you can:
1.Assign objectB id to objectA
var b = (objectB)cmbBObjects.selectedItem;
objectA.myObjectBId = b.Id;
2.Or load objectB from dataContext and than assign to objectA:
var b = (objectB)cmbBObjects.selectedItem;
var dcB = context.ObjectBs.Single(x=> x.Id == b.Id);
objectA.myObjectB = dcB;
Just try my suggestions and come back with results, because i don't know exactly.
Hope this help.

Categories