Introduction
Pretty often, we have to save a master object with a collection of children.
Given the following model of Person
with multiple Phone
s ...
public class Phone
{
public int Id { get; set; }
public string Number { get; set; }
public string Note { get; set; }
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Phone> Phones { get; set; }
}
... code that saves person
might look like this:
public void Save(Person person)
{
... save person object first
... this code is not shows for simplicity
var phonesInDb = DataContext.Phone
.Where(p => p.PersonId == person.Id)
.ToList();
var toDelete = phonesInDb
.Where(p => !person.Phones.Any(h => h.Id == p.Id))
.ToList();
DataContext.Phone.DeleteAllOnSubmit(toDelete);
var toInsert = person.Phones
.Where(p => !phonesInDb.Any(h => h.Id == p.Id))
.Select(p => new Db.Phone
{
PersonId = person.Id,
Number = p.Number,
Note = p.Note
})
.ToList();
DataContext.Phone.InsertAllOnSubmit(toInsert);
foreach (var dbPhone in phonesInDb)
{
var newPhone = person.Phones.Where(p => p.Id == dbPhone.Id).SingleOrDefault();
if (newPhone != null)
{
newPhone.Number = newPhone.Number;
newPhone.Note = mod.Note;
}
}
DataContext.SubmitChanges();
}
The problem here is that this code is pretty long and you might have to duplicate it for all child/parent objects in your project.
The code can be much shorter:
public void Save(Person person)
{
... save person object first
... this code is not shows for simplicity
var phonesInDb = DataContext.Phone
.Where(p => p.PersonId == person.Id)
.ToList();
Ctx.InsertUpdateDelete(person.Phones, phonesInDb,
(m, d) => (m.Id == d.Id),
(m, d) =>
{
d.PersonId = person.Id;
d.Number = m.Number;
d.Note = m.Note;
});
DataContext.SubmitChanges();
}
If you add the following generic function to your DataContext
class:
public partial class DataContext
{
public void InsertUpdateDelete<TModel, TDatabase>
(IEnumerable<TModel> mod, IEnumerable<TDatabase> db,
Func<TModel, TDatabase, bool> match, Action<TModel,
TDatabase> convert) where TDatabase : class, new()
{
var table = this.GetTable<TDatabase>();
var toDelete = db.Where(d => !mod.Any(m => match(m, d)));
table.DeleteAllOnSubmit(toDelete);
var toInsert = mod
.Where(m => !db.Any(d => match(m, d)))
.Select(m =>
{
var newDb = new TDatabase();
convert(m, newDb);
return newDb;
});
table.InsertAllOnSubmit(toInsert);
foreach (var d in db)
{
var m = mod.Where(x => match(x, d)).SingleOrDefault();
if (m != null) convert(m, d);
}
}
}
The good thing is that you can use InsertUpdateDelete
for all parent/child relations in your project.
mod
and db
are collection of model and database objects, database objects are updated/deleted/inserted based model objects.
match
is that function that finds corresponding pairs of model
and db
objects.
convert
is the translation from model
into db
object.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.