NHibernate 5.1 ManyToOne - delete orphan not working as expected - nhibernate

I have following entities:
public class Person {
public int Id {get;set;}
public String Name {get;set;}
public Passport Passport {get;set;}
}
public class Passport {
public int Id {get;set;}
public String PassportNo {get;set;}
// ... other properties
}
and following mapping (for Person):
ManyToOne(x => x.Passport, m =>
{
m.Column("PassportId");
m.Lazy(LazyRelation.NoLazy);
m.Unique(true);
m.Cascade(Cascade.All | Cascade.DeleteOrphans);
});
DB schema:
Table Person:
Id | Name | PassportId
Table Passport:
Id | PassportNo | other props.
As we can see, Person has it's passport, but passport has no idea about its owner, which is behaviour I want. There are 2 more assumptions:
Person can have only 1 passport at a time
Passport can NOT exists without person
Problem is, when I assign new Passport to a Person, the old Passport remains in DB.
person.Passport = new Passport() { PassportNo = "AB 123456" };
// ...
session.Flush();
session.Commit();
SQL queries that are generated are INSERT and UPDATE (inserts new Passport, and updates Person with new Passport) - however there is no DELETE on orphaned, old passport.
The workaround I found is to set current Passport to null, call session.Flush(), and assign new Passport, like this:
person.Passport = null;
session.Flush();
person.Passport = new Passport() { PassportNo = "AB 123456" };
// ...
session.Flush();
session.Commit();
however IMO it is a hacky solution.
So, summing it up:
am I missing something in my mapping?
is above behaviour a bug in NH?
can it be solved without hacky Flush()?

After long searching for solution, I found that there is a Join mapping, which perfectly fits above scenario.
Hope it helps someone.
More info here:
http://notherdev.blogspot.com/2012/01/mapping-by-code-join.html

Related

Batch Class Add contact to Account

I have created 20 records with the 'name=SampleAccountOne'. I am trying to create a batch class that will add a given contact to the 20 records. Stuck with syntax and where to go. Any help in the right direction is greatly appreciated.
global class UpdateProjectNameBatch implementsDatabase.Batchable<sObject> {
List<Contact> conList = new conList<Contact>();
String query = 'Select Id,Name FROM Account WHERE Name = \'SampleAccountOne\''
global Database.QueryLocator start(Database.BatchableContext bc){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc,List<sObject> batch){
for(Contact c : conList){
batch.c = 'New Contact Name';
}
}
global void finish(){
}
}
I believe you are trying to associate a single contact to multiple accounts. This functionality was released in Spring 16' and is implemented through a Salesforce Junction object - AccountContactRelation.
I assume you have already enabled this functionality through the UI and a parent Account is declared for this Contact.
I have modified your code to associate the contact to all 20 account.
global class UpdateProjectNameBatch implements Database.Batchable
<sObject>
{ ID conId = '0037F00000IfCCKQA3'; //Add the contact Id here
List<AccountContactRelation> ListInsertion = new List<AccountContactRelation>();
String query = 'Select Id,Name FROM Account WHERE Name = \'SampleAccountOne\'';
global Database.QueryLocator start(Database.BatchableContext bc)
{
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc,List<Account> batch){
for (Account a : batch)
{
AccountContactRelation c = new AccountContactRelation();
c.AccountId = a.id;
c.contactId = conId;
ListInsertion.add(c);
}
Insert ListInsertion;
}
global void finish(Database.BatchableContext bc)
{
//DoNothing.
}
}

How to get single row from SQLite database in Windows Store apps?

If I want single primitive value like int, string, float etc I can do like this.
using (var db = new SQLiteConnection(DbPath))
{
double i = db.CreateCommand("select salary from PersonMaster where personId = ?", 9).ExecuteScalar<double>();
}
If I try to return whole object of person master i.e. single row the below code returns null
using (var db = new SQLiteConnection(DbPath))
{
PersonMaster objPersonMaster = db.CreateCommand("select * from PersonMaster where personId = ?", 9).ExecuteScalar<PersonMaster>();
}
I compulsory have to use this
using (var db = new SQLiteConnection(DbPath))
{
List<PersonMaster> lstPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9);
PersonMaster objPersonMaster = lstPersonMaster.First();
}
Is there any way to get single row as object, rather than dealing with List<T>
I am assuming you are using SQLite-Net. If that is the case you can use the Find method. Find gets an object using its primary key.
The personId field needs the PrimaryKey attribute as follows:
public class PersonMaster
{
[PrimaryKey]
public int personId { get; set; }
public string name { get; set; }
public decimal salary { get; set; }
}
Then you can use Find like so:
// get person 9
PersonMaster person9 = db.Find<PersonMaster>(9);
You can either use "TOP(1) yourquery" or "yourquery LIMIT 1"
if you just want to get rid of the list step, you can do it directly:
PersonMaster objPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9).First();
Of course you have to deal with a possible exception in case nothing is returned, but you should do this also with the list approach anyway.

NHibvernate 3.2 many to many not populating join table

I have two classes, user and role, defined as:
public class User : Entity
{
// other properties ...
public virtual string Username
public virtual ICollection<Role> Roles { get; set; }
}
public class Role : Entity
{
public virtual string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
In my mapping code, I have the following:
mapper.Class<User>(map =>
{
map.Bag(x=>x.Roles,
cm=>
{
cm.Table("UserRole");
cm.Cascade(Cascade.All);
cm.Key(k => k.Column("[User]"));
},
em=>
{
em.ManyToMany(mm =>
{
mm.Column("[Role]");
});
});
});
mapper.Class<Role>(map =>
{
map.Bag(x=>x.Users,
cm=>
{
cm.Inverse(true);
cm.Table("UserRole");
cm.Key(k=>k.Column("[Role]"));
},
em =>
{
em.ManyToMany(mm =>
{
mm.Column("[User]");
});
});
});
The mappings generate the expected schema, but the join table is never populated. Adding a new user with a new Role in its collection persists the role and then the user to the appropriate tables, but the join table is left empty. Why?
Edit: I still have not made any progress on this. I'm absolutely sure the mapping is correct, and the correct schema is generated, but the join table simply isn't populated. For test purposes, I'm generating entities using NBuilder like so:
var roles = new Role[]
{
new Role("Admin"),
new Role("Manager"),
new Role("User")
};
var users = Builder<User>.CreateListOfSize(10)
.TheFirst(1)
.Do(x =>
{
x.Roles.Add(roles[0]);
x.Roles.Add(roles[1]);
roles[0].Users.Add(x);
roles[1].Users.Add(x);
})
.All()
.With(x => x.Id = 0)
.And(x => x.Version = 0)
.And(x => x.Username = "test user")
.And(x => x.Password = "test password")
.Do(x =>
{
x.Roles.Add(roles[2]);
roles[2].Users.Add(x);
}
.Build();
foreach (var u in users) session.Save(u);
The User and Role entities are persisted correctly, but the join table remains empty. This means I cannot effective query the roles for a given user later, which nullifies the point.
Make sure you have both classes referencing each other.
I think that code, similar to one below, should work for you:
role.Users.Add(user);
user.Roles.Add(role);
session.Save(user); // NH only saves user and role, so it can get auto-generated identity fields
session.Flush(); // NH now can save into cross-ref table, because it knows required information (Flush is also called inside of Transaction.Commit())
I found a good answer to a question about many-to-many with lot of explanations and quotes from NH documentation. I think it worth to read it.
[EDIT]
In answer to this somewhat similar question there is discussion in which need for explicit transaction to save into cross-table is mentioned.
I also edited code above with adding session.Flush() to reflect my findings.
I ended up downloading the NHibernate source and referencing that directly so I could step through it. It turns out that it had something to do with the fact that my code for generating the test data was not wrapped in an explicit session transaction. Once I added that, it was fine. I'd love to see some kind of explanation on this, as I wasn't able to follow the code very clearly, but I'm at least satisfied that the problem is solved.

Join query in Nhibernate criteria or in Nhibernate Linq

I have a query I am trying to run but I'm not getting desired result.
select * from employee_login e
left join employee_attendance ea on
e.emp_id = ea.EmpId and dated = '2012-01-11'
The Linq query which I tried with Nhibernate is
var attendance = from emp in session.Query<Employee>()
join empatten in session.Query<EmployeeAttendance>()
on emp.emp_id equals empatten.EmpId into atts
from ur in atts.DefaultIfEmpty()
select new { ur };
In the var attendance resultview. How can I achieve these two things?
a left join over employee and employeeattendance ( employee is the left table)
a and condition on the join not over the join result .
I'm pretty new to this situation using Linq or detached criteria; a detached criteria would be a preferable answer.
Here are the models:
public class EmployeeAttendance
{
public virtual string No_ { get; set; }
public virtual Employee Employee { get; set; }
}
public class Employee
{
public virtual string emp_id { get; set; }
public virtual ISet<EmployeeAttendance> Attendances { get; set; }
public Employee()
{
Attendances = new HashedSet<EmployeeAttendance>();
}
}
The Mapping is :
public class EmployeeAttendanceMap:ClassMap<EmployeeAttendance>
{
public EmployeeAttendanceMap()
{
Table("Employee_Attendance");
Id(x => x.No_).GeneratedBy.Assigned();
References(x => x.Employee).Column("emp_id");
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Table("employee_login");
Id(x => x.emp_id).Column("emp_id").GeneratedBy.Assigned();
HasMany(x => x.Attendances).KeyColumn("No_").Cascade.All();
}
}
The Employee is the primary table and AttendanceLeave has the foreign key as EmpId from Employee Table
Edit : I tried this also in my last attempt:
ICriteria criteria = session.CreateCriteria(typeof(Employee), "emp")
.CreateAlias("EmployeeAttendance", "Attendance", CriteriaSpecification.LeftJoin
, Restrictions.Eq("Attendance.Dated", DateTime.Parse("2012-1-11")));
but I ended up getting error as :
could not resolve property: EmployeeAttendance of: Royal.Data.Core.Domain.Employee
It looks like you want to get employees on leave as of a certain date. I think this would work, though I've never used the between expression in this way before:
var detached = DetachedCriteria.For<AttendanceLeave>("al")
.Add(Expression.Between('2012-01-11', "LeaveFrom", "LeaveTo")) //this should be a DateTime
.Add(Restrictions.EqProperty ("al.EmpId", "e.emp_id")) //make sure to use "e" for employee criteria alias
.SetProjection (Projections.Count ("al.EmpId"));
var employeesOnLeave = session.CreateCriteria<Employee>("e")
.Add(Restrictions.Gt(Projections.Subquery(detached), 0))
.List();
You'll still get the complete set of leaves on each employee, but it should be the employee you want.
update - looking at your comment, it seems something like this could be what you're after:
DateTime dateInQuestion = new DateTime(2012, 1, 11);
var employeesOnLeaveAsOfDateInQuestion =
session.CreateCriteria<Employee>("e")
.CreateCriteria("e.Attendances", "ea"
, NHibernate.SqlCommand.JoinType.LeftOuterJoin
, Restrictions.Between(dateInQuestion, "ea.LeaveFrom", "ea.LeaveTo"))
.List<Employee>();
This seems to work - but you need to make sure the entities you get back are not cached, otherwise cached copies w/ the full collection will be returned. This is what I tested with - not exactly like your situation because collection is maintained through a link table, but I think it will work the same either way - you may need to evict the collection specifically with a straight one to many though (the EvictCollection method is found on the session factory, not the session). You should need this bit for testing only (in my tests, the database only lives as long as the session). There is also a QueryOver example in the gist if you'd prefer to solve it that way.

How to update only one field using Entity Framework?

Here's the table
Users
UserId
UserName
Password
EmailAddress
and the code..
public void ChangePassword(int userId, string password){
//code to update the password..
}
Ladislav's answer updated to use DbContext (introduced in EF 4.1):
public void ChangePassword(int userId, string password)
{
var user = new User() { Id = userId, Password = password };
using (var db = new MyEfContextName())
{
db.Users.Attach(user);
db.Entry(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();
}
}
You can tell entity-framework which properties have to be updated in this way:
public void ChangePassword(int userId, string password)
{
var user = new User { Id = userId, Password = password };
using (var context = new ObjectContext(ConnectionString))
{
var users = context.CreateObjectSet<User>();
users.Attach(user);
context.ObjectStateManager.GetObjectStateEntry(user)
.SetModifiedProperty("Password");
context.SaveChanges();
}
}
In Entity Framework Core, Attach returns the entry, so all you need is:
var user = new User { Id = userId, Password = password };
db.Users.Attach(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();
You have basically two options:
go the EF way all the way, in that case, you would
load the object based on the userId provided - the entire object gets loaded
update the password field
save the object back using the context's .SaveChanges() method
In this case, it's up to EF how to handle this in detail. I just tested this, and in the case I only change a single field of an object, what EF creates is pretty much what you'd create manually, too - something like:
`UPDATE dbo.Users SET Password = #Password WHERE UserId = #UserId`
So EF is smart enough to figure out what columns have indeed changed, and it will create a T-SQL statement to handle just those updates that are in fact necessary.
you define a stored procedure that does exactly what you need, in T-SQL code (just update the Password column for the given UserId and nothing else - basically executes UPDATE dbo.Users SET Password = #Password WHERE UserId = #UserId) and you create a function import for that stored procedure in your EF model and you call this function instead of doing the steps outlined above
i'm using this:
entity:
public class Thing
{
[Key]
public int Id { get; set; }
public string Info { get; set; }
public string OtherStuff { get; set; }
}
dbcontext:
public class MyDataContext : DbContext
{
public DbSet<Thing > Things { get; set; }
}
accessor code:
MyDataContext ctx = new MyDataContext();
// FIRST create a blank object
Thing thing = ctx.Things.Create();
// SECOND set the ID
thing.Id = id;
// THIRD attach the thing (id is not marked as modified)
db.Things.Attach(thing);
// FOURTH set the fields you want updated.
thing.OtherStuff = "only want this field updated.";
// FIFTH save that thing
db.SaveChanges();
While searching for a solution to this problem, I found a variation on GONeale's answer through Patrick Desjardins' blog:
public int Update(T entity, Expression<Func<T, object>>[] properties)
{
DatabaseContext.Entry(entity).State = EntityState.Unchanged;
foreach (var property in properties)
{
var propertyName = ExpressionHelper.GetExpressionText(property);
DatabaseContext.Entry(entity).Property(propertyName).IsModified = true;
}
return DatabaseContext.SaveChangesWithoutValidation();
}
"As you can see, it takes as its second parameter an expression of a
function. This will let use this method by specifying in a Lambda
expression which property to update."
...Update(Model, d=>d.Name);
//or
...Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
( A somewhat similar solution is also given here: https://stackoverflow.com/a/5749469/2115384 )
The method I am currently using in my own code, extended to handle also (Linq) Expressions of type ExpressionType.Convert. This was necessary in my case, for example with Guid and other object properties. Those were 'wrapped' in a Convert() and therefore not handled by System.Web.Mvc.ExpressionHelper.GetExpressionText.
public int Update(T entity, Expression<Func<T, object>>[] properties)
{
DbEntityEntry<T> entry = dataContext.Entry(entity);
entry.State = EntityState.Unchanged;
foreach (var property in properties)
{
string propertyName = "";
Expression bodyExpression = property.Body;
if (bodyExpression.NodeType == ExpressionType.Convert && bodyExpression is UnaryExpression)
{
Expression operand = ((UnaryExpression)property.Body).Operand;
propertyName = ((MemberExpression)operand).Member.Name;
}
else
{
propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
}
entry.Property(propertyName).IsModified = true;
}
dataContext.Configuration.ValidateOnSaveEnabled = false;
return dataContext.SaveChanges();
}
New EF Core 7 native feature — ExecuteUpdate:
Finally! After a long wait, EF Core 7.0 now has a natively supported way to run UPDATE (and also DELETE) statements while also allowing you to use arbitrary LINQ queries (.Where(u => ...)), without having to first retrieve the relevant entities from the database: The new built-in method called ExecuteUpdate — see "What's new in EF Core 7.0?".
ExecuteUpdate is precisely meant for these kinds of scenarios, it can operate on any IQueryable instance, and lets you update specific columns on any number of rows, while always issuing a single UPDATE statement behind the scenes, making it as efficient as possible.
Usage:
Let's take OP's example — i.e. updating the password column of a specific user:
dbContext.Users
.Where(u => u.Id == someId)
.ExecuteUpdate(b =>
b.SetProperty(u => u.Password, "NewPassword")
);
As you can see, calling ExecuteUpdate requires you to make calls to the SetProperty method, to specify which property to update, and also what new value to assign to it.
EF Core will translate this into the following UPDATE statement:
UPDATE [u]
SET [u].[Password] = "NewPassword"
FROM [Users] AS [u]
WHERE [u].[Id] = someId
Also, ExecuteDelete for deleting rows:
There's also a counterpart to ExecuteUpdate called ExecuteDelete, which, as the name implies, can be used to delete a single or multiple rows at once without having to first fetch them.
Usage:
// Delete users that haven't been active in 2022:
dbContext.Users
.Where(u => u.LastActiveAt.Year < 2022)
.ExecuteDelete();
Similar to ExecuteUpdate, ExecuteDelete will generate DELETE SQL statements behind the scenes — in this case, the following one:
DELETE FROM [u]
FROM [Users] AS [u]
WHERE DATEPART(year, [u].[LastActiveAt]) < 2022
Other notes:
Keep in mind that both ExecuteUpdate and ExecuteDelete are "terminating", meaning that the update/delete operation will take place as soon as you call the method. You're not supposed to call dbContext.SaveChanges() afterwards.
If you're curious about the SetProperty method, and you're confused as to why ExectueUpdate doesn't instead receive a member initialization expression (e.g. .ExecuteUpdate(new User { Email = "..." }), then refer to this comment (and the surrounding ones) on the GitHub issue for this feature.
Furthermore, if you're curious about the rationale behind the naming, and why the prefix Execute was picked (there were also other candidates), refer to this comment, and the preceding (rather long) conversation.
Both methods also have async equivalents, named ExecuteUpdateAsync, and ExecuteDeleteAsync respectively.
In EntityFramework Core 2.x there is no need for Attach:
// get a tracked entity
var entity = context.User.Find(userId);
entity.someProp = someValue;
// other property changes might come here
context.SaveChanges();
Tried this in SQL Server and profiling it:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [User] SET [someProp] = #p0
WHERE [UserId] = #p1;
SELECT ##ROWCOUNT;
',N'#p1 int,#p0 bit',#p1=1223424,#p0=1
Find ensures that already loaded entities do not trigger a SELECT and also automatically attaches the entity if needed (from the docs):
Finds an entity with the given primary key values. If an entity with the given primary key values is being tracked by the context, then it is returned immediately without making a request to the database. Otherwise, a query is made to the database for an entity with the given primary key values and this entity, if found, is attached to the context and returned. If no entity is found, then null is returned.
I'm late to the game here, but this is how I am doing it, I spent a while hunting for a solution I was satisified with; this produces an UPDATE statement ONLY for the fields that are changed, as you explicitly define what they are through a "white list" concept which is more secure to prevent web form injection anyway.
An excerpt from my ISession data repository:
public bool Update<T>(T item, params string[] changedPropertyNames) where T
: class, new()
{
_context.Set<T>().Attach(item);
foreach (var propertyName in changedPropertyNames)
{
// If we can't find the property, this line wil throw an exception,
//which is good as we want to know about it
_context.Entry(item).Property(propertyName).IsModified = true;
}
return true;
}
This could be wrapped in a try..catch if you so wished, but I personally like my caller to know about the exceptions in this scenario.
It would be called in something like this fashion (for me, this was via an ASP.NET Web API):
if (!session.Update(franchiseViewModel.Franchise, new[]
{
"Name",
"StartDate"
}))
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
Entity framework tracks your changes on objects that you queried from database via DbContext. For example if you DbContext instance name is dbContext
public void ChangePassword(int userId, string password){
var user = dbContext.Users.FirstOrDefault(u=>u.UserId == userId);
user.password = password;
dbContext.SaveChanges();
}
I know this is an old thread but I was also looking for a similar solution and decided to go with the solution #Doku-so provided. I'm commenting to answer the question asked by #Imran Rizvi , I followed #Doku-so link that shows a similar implementation. #Imran Rizvi's question was that he was getting an error using the provided solution 'Cannot convert Lambda expression to Type 'Expression> [] ' because it is not a delegate type'. I wanted to offer a small modification I made to #Doku-so's solution that fixes this error in case anyone else comes across this post and decides to use #Doku-so's solution.
The issue is the second argument in the Update method,
public int Update(T entity, Expression<Func<T, object>>[] properties).
To call this method using the syntax provided...
Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
You must add the 'params' keyword in front of the second arugment as so.
public int Update(T entity, params Expression<Func<T, object>>[] properties)
or if you don't want to change the method signature then to call the Update method you need to add the 'new' keyword, specify the size of the array, then finally use the collection object initializer syntax for each property to update as seen below.
Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });
In #Doku-so's example he is specifying an array of Expressions so you must pass the properties to update in an array, because of the array you must also specify the size of the array. To avoid this you could also change the expression argument to use IEnumerable instead of an array.
Here is my implementation of #Doku-so's solution.
public int Update<TEntity>(LcmsEntities dataContext, DbEntityEntry<TEntity> entityEntry, params Expression<Func<TEntity, object>>[] properties)
where TEntity: class
{
entityEntry.State = System.Data.Entity.EntityState.Unchanged;
properties.ToList()
.ForEach((property) =>
{
var propertyName = string.Empty;
var bodyExpression = property.Body;
if (bodyExpression.NodeType == ExpressionType.Convert
&& bodyExpression is UnaryExpression)
{
Expression operand = ((UnaryExpression)property.Body).Operand;
propertyName = ((MemberExpression)operand).Member.Name;
}
else
{
propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
}
entityEntry.Property(propertyName).IsModified = true;
});
dataContext.Configuration.ValidateOnSaveEnabled = false;
return dataContext.SaveChanges();
}
Usage:
this.Update<Contact>(context, context.Entry(modifiedContact), c => c.Active, c => c.ContactTypeId);
#Doku-so provided a cool approach using generic's, I used the concept to solve my issue but you just can't use #Doku-so's solution as is and in both this post and the linked post no one answered the usage error questions.
Combining several suggestions I propose the following:
async Task<bool> UpdateDbEntryAsync<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class
{
try
{
var entry = db.Entry(entity);
db.Set<T>().Attach(entity);
foreach (var property in properties)
entry.Property(property).IsModified = true;
await db.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("UpdateDbEntryAsync exception: " + ex.Message);
return false;
}
}
called by
UpdateDbEntryAsync(dbc, d => d.Property1);//, d => d.Property2, d => d.Property3, etc. etc.);
Or by
await UpdateDbEntryAsync(dbc, d => d.Property1);
Or by
bool b = UpdateDbEntryAsync(dbc, d => d.Property1).Result;
I use ValueInjecter nuget to inject Binding Model into database Entity using following:
public async Task<IHttpActionResult> Add(CustomBindingModel model)
{
var entity= await db.MyEntities.FindAsync(model.Id);
if (entity== null) return NotFound();
entity.InjectFrom<NoNullsInjection>(model);
await db.SaveChangesAsync();
return Ok();
}
Notice the usage of custom convention that doesn't update Properties if they're null from server.
ValueInjecter v3+
public class NoNullsInjection : LoopInjection
{
protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
{
if (sp.GetValue(source) == null) return;
base.SetValue(source, target, sp, tp);
}
}
Usage:
target.InjectFrom<NoNullsInjection>(source);
Value Injecter V2
Lookup this answer
Caveat
You won't know whether the property is intentionally cleared to null OR it just didn't have any value it. In other words, the property value can only be replaced with another value but not cleared.
_context.Users.UpdateProperty(p => p.Id, request.UserId, new UpdateWrapper<User>()
{
Expression = p => p.FcmId,Value = request.FcmId
});
await _context.SaveChangesAsync(cancellationToken);
Update Property is an extension method
public static void UpdateProperty<T, T2>(this DbSet<T> set, Expression<Func<T, T2>> idExpression,
T2 idValue,
params UpdateWrapper<T>[] updateValues)
where T : class, new()
{
var entity = new T();
var attach = set.Attach(entity);
attach.Property(idExpression).IsModified = false;
attach.Property(idExpression).OriginalValue = idValue;
foreach (var update in updateValues)
{
attach.Property(update.Expression).IsModified = true;
attach.Property(update.Expression).CurrentValue = update.Value;
}
}
And Update Wrapper is a class
public class UpdateWrapper<T>
{
public Expression<Func<T, object>> Expression { get; set; }
public object Value { get; set; }
}
I was looking for same and finally I found the solution
using (CString conn = new CString())
{
USER user = conn.USERs.Find(CMN.CurrentUser.ID);
user.PASSWORD = txtPass.Text;
conn.SaveChanges();
}
believe me it work for me like a charm.
public async Task<bool> UpdateDbEntryAsync(TEntity entity, params Expression<Func<TEntity, object>>[] properties)
{
try
{
this.Context.Set<TEntity>().Attach(entity);
EntityEntry<TEntity> entry = this.Context.Entry(entity);
entry.State = EntityState.Modified;
foreach (var property in properties)
entry.Property(property).IsModified = true;
await this.Context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
throw ex;
}
}
public void ChangePassword(int userId, string password)
{
var user = new User{ Id = userId, Password = password };
using (var db = new DbContextName())
{
db.Entry(user).State = EntityState.Added;
db.SaveChanges();
}
}