简体   繁体   中英

Compare List to Database records, if exists - update, if new - create (EF Core)

I have a class, let's say (TimePassed is int value indicating seconds passed):

public class DataLogModel
{
   public int Id { get; set; }
   public string LogName { get; set; }
   public int TimePassed { get; set; }
   public DateTime RecordDate { get; set; }
}

Then I am adding data to it in application. Let's say data in database looks like this (I don't have ID's in my "data for database" records, can compare only by name and Date):

1 Signal received   40    14.4.2021
2 Procedure started 50    4.2.2021
3 Motor stopped     70    8.1.2021

Then I am passing this data to Database using EF Core. At this stage, before passing, I need to perform a check if certain records already exist in database and if exist update time value by summarizing to already existing in database and if record is new, then create new item.

I have came up with this solution, that is able to add new records, but I can't get updating logic working. I have tried different solutions but non of them worked. My latest try can be found in code below. Would be glad to get some hint how it can be done?

Current method for recording data to database (without update logic working, I have commented my attempt out in code). I am passing newly recorded list as parameter in method:

public void ListToDatabase(IEnumerable<DataLogModel> trackedLogs)
{
  using (var db = new SQLDBContext.SQLDBContext())
  {
    // Here is my attempt with foreach, to get already existing records and update TimePassed value if found
    foreach (DataLogModel item in trackedLogs)
    {
      if (db.DataLogModel.Any(w => w.LogName == item.LogName && w.RecordDate == item.RecordDate.Date))
      {
        DataLogModel updateMe = db.DataLogModel
          .Where(w => w.LogName == item.LogName && w.RecordDate == item.RecordDate.Date).First();

        // Here I need to get existing record in database and summarize with
        // value for corresponding item from trackedLogs list passed as 
        // parameter to this method
        updateMe.TimePassed = updateMe.TimePassed + item.TimePassed;

        db.Update(db.ActivityLogModel);
      }
    }
    // Here is the end of my attempt

    // If no update needed below two lines works fine
    db.AddRange(trackedLogs);
    db.SaveChanges();
  }
}

Can't you just use this pattern?

foreach(var item in updates) {

    // search for existing entity.
    Entity entity = db.Entities.Where(x => x.keyValue == item.keyValue).FirstOrDefault();

    if(entity == null) {

        // no existing entity with this key value, insert.
        entity = new Entity(item);
        db.Entities.Add(entity);

    } else {
        // update existing entity.
        entity.property = item.property;
    }
}

db.SaveChanges();

If you need to handle a lot of records probably you can do it with this great extension . If you have a primary key, you can solve it just using the "BulkInsertOrUpdate" method. In your case you can solve it like this:

// Only one call to the Db
var toUpdate = (from log in db.DataLogModel
              where items.Any(i => i.LogName == log.LogName && i.RecordDate == log.RecordDate.Date)
              select log).ToList();
// Locally
var toInsert = (from log in trackedLogs
              where toUpdate.All(i => i.LogName != log.LogName && i.RecordDate != log.RecordDate.Date)
              select log).ToList();
              
// Finally
db.BulkUpdate(toUpdate);
db.BulkInsert(toInsert);

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM