Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a LINQ or DBContext extension method to get an element if not exist then create with data in predicate (FirstOrCreate)

I'm trying to add a LINQ or DbContext extension method to get an element (FirstOrDefault) but if one does not already exist then create a new instance with data (FirstOrCreate) instead of returning null.

is this possible?

i.e.:

public static class LINQExtension
{
    public static TSource FirstOrCreate<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate)
    {
        if (source.First(predicate) != null)
        {
            return source.First(predicate);
        }
        else
        {
            return // ??? 
        }
    }
}

and a usage could be:

using (var db = new MsBoxContext())
{
    var status = db.EntitiesStatus.FirstOrCreate(s => s.Name == "Enabled"); 
    //Here we should get the object if we find one
    //and if it doesn't exist create and return a new instance

    db.Entities.Add(new Entity()
    {
         Name = "New Entity",
         Status = status
    });
}

I hope that you understand my approach.

like image 595
Nano Sassaroli Avatar asked Nov 02 '22 21:11

Nano Sassaroli


1 Answers

public static class LINQExtension
{
    public static TSource FirstOrCreate<TSource>(
               this IQueryable<TSource> source, 
               Expression<Func<TSource, bool>> predicate, 
               Func<T> defaultValue)
    {
        return source.FirstOrDefault(predicate) ?? defaultValue();
    }
}

usage

var status = db.EntitiesStatus.FirstOrCreate(s => s.Name == "Enabled", 
                 () => new EntityStatus {Name = "Enabled"});

However you must note that this will not work quite like FirstOrDefault().

If you did the following

var listOfStuff = new List<string>() { "Enabled" };
var statuses = from s in listOfStuff
               select db.EntitiesStatus.FirstOrCreate(s => s.Name == "Enabled", 
                        () => new EntityStatus {Name = "Enabled"});

You would get O(n) hits to the database.

However I suspect if you did...

var listOfStuff = new List<string>() { "Enabled" };
var statuses = from s in listOfStuff
               select db.EntitiesStatus.FirstOrDefault(s => s.Name == "Enabled") 
                             ?? new EntityStatus {Name = "Enabled"};

It is plausible it could work...

like image 173
Aron Avatar answered Nov 11 '22 07:11

Aron