Method to save child objects
/// &lt;summary&gt;
/// Saves the list of data sources. This assumes that the ModelTemplateID, SetNumber and TaskNumber
/// are already properly set. Adds a new record to the DataSourceGroups table if necessary.
/// &lt;/summary&gt;
/// &lt;param name="dataSources"&gt;The list of data sources to save&lt;/param&gt;
public void SaveSet(IEnumerable&lt;DataSource&gt; dataSources)



The method name is telling a lie. SaveSet would be appropriate if the method took an IEnumerable&lt;Set&gt; sets parameter. I would have called the method SaveDataSources.

Per the XML comments, the method is making assumptions, but it does nothing to verify these assumptions, and since the method has no return type, the only way you can fail is by letting it throw - throwing is good in this situation, however it's best to fail early, if possible before you even create the context instance.

This is done with a guard clause at the top of your method, that aborts the call if an argument is invalid - for example:

if (dataSources.Any(dataSource =&gt; 
       dataSource.ModelTemplateID == default(typeof(dataSource.ModelTemplateID))
    || dataSource.SetNumber == default(typeof(dataSource.ModelTemplateID))
    || dataSource.TaskNumber == default(typeof(dataSource.TaskNumber))))
{
    throw new ArgumentException("Members 'ModelTemplateID', 'SetNumber' and 'TaskNumber' not set.", "dataSources");
}


This makes your code throw a more meaningful exception, instead of adding half the items, throwing some foreign key exception and then disposing the context without persisting anything.




using (var db = _contextFactory.GetContext())



While a conveniently short identifier, db is a misleading name to use for a DbContext; it's more of a context than a database, so context would be more appropriate.

I like that the method isn't directly responsible for creating the DbContext instance, however GetContext() sounds like you're not creating anything, rather just returning an existing instance - which is counter-intuitive in the context (pun not intended) of a factory. CreateContext would be better, and since _contextFactory is already a quite descriptive name, a Create method wouldn't be any less clear:

using (var context = _contextFactory.Create())
{





foreach (var dataSource in dataSources)
{
    var dataSourceFromDb =
        db.DataSources.FirstOrDefault(x =&gt; x.DataSourceID == dataSource.DataSourceID);



Unless I look at your schema and see that DataSourceID is the entity's primary key, I have no way of being sure that you're expecting only a single record, because FirstOrDefault could just as well operate on 20 entities and only return the first that matches the criteria.

This would be less ambiguous, because if more than 1 entity is returned, SingleOrDefault would throw an exception:

foreach (var dataSource in dataSources)
{
    var dataSourceFromDb = 
            context.DataSources
                   .SingleOrDefault(e =&gt; e.DataSourceID == dataSource.DataSourceID);




This part looks like it belongs in another method:


        if (dataSourceFromDb == null)
        { // not in database yet, add it
            var dataSourceGroupFromDb =
                db.DataSourceGroups.SingleOrDefault(
                    x =&gt; x.ModelTemplateID == dataSource.ModelTemplateID &amp;&amp;
                         x.SetNumber == dataSource.SetNumber &amp;&amp;
                         x.TaskNumber == dataSource.TaskNumber);
            if (dataSourceGroupFromDb == null)
            { // Add new DataSourceGroup to db
                db.DataSourceGroups.Add(new DataSourceGroup
                {
                    ModelTemplateID = dataSource.ModelTemplateID,
                    SetNumber = dataSource.SetNumber,
                    TaskNumber = dataSource.TaskNumber
                });
            }
            db.DataSources.Add(dataSource);



I don't like the comments on the same line as the scope-opening brace { //, and these comments wouldn't be needed at all if you extracted the method; the added level of abstraction would speak for itself:

if (dataSourceFromDb == null)
{
    EnsureDataSourceGroupExists(context, dataSource);
    context.DataSources.Add(dataSource)
}
else
{
    dataSourceFromDb.QueryID = dataSource.QueryID;
    dataSourceFromDb.SourceType = dataSource.SourceType;
    dataSourceFromDb.TargetFormat = dataSource.TargetFormat;
    dataSourceFromDb.SourcePath = dataSource.SourcePath;
    dataSourceFromDb.TargetPath = dataSource.TargetPath;
}

context.SaveChanges();


Notice the how the update code is simply copying the values from dataSource into the members of dataSourceFromDb - that entity is already attached and managed by the change tracker. Why complicate things? It's there, might as well use it!

One thing your code also assumes, is that SaveChanges will insert the DataSourceGroup entity before it inserts dataSource. I don't know about EF6, but in other versions one cannot make that assumption, so EnsureDataSourceGroupExists would call SaveChanges on the context if a new entity was created. Not doing this is like asking for a foreign key violation.