Общий способ найти или создать объект в LINQ to SQL? - PullRequest
3 голосов
/ 24 апреля 2009

Довольно часто в моем LINQ to SQL коде мне нужно "найти или создать" сущность как таковую:

var invoiceDb = ctx.Invoices.FirstOrDefault(a => a.InvoicerId == InvoicerId &&
                                                 a.Number == invoiceNumber);
if (invoiceDb == null)
{
    invoiceDb = new Invoice();
    invoiceDb.Number = invoiceNumber;
    ctx.Invoices.InsertOnSubmit(invoiceDb);
}

Я хочу сделать этот метод универсальным ... Есть хорошие идеи?

Ответы [ 5 ]

2 голосов
/ 05 октября 2010

VB.NET версия:

Module dbi
    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean), _
        ByVal create As Action(Of T)) _
        As T

        Dim val As T = table.FirstOrDefault(find)
        If val Is Nothing Then
            val = New T()
            create(val)
            table.InsertOnSubmit(val)
        End If
        Return val
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindOrCreate( _
        Of T As {Class, New})(ByVal table As Data.Linq.Table(Of T), _
        ByVal find As Func(Of T, Boolean)) _
        As T

        Return FindOrCreate(table, find, Function(a))
    End Function

End Module
2 голосов
/ 24 апреля 2009

Я придумал эти методы расширения, которые, кажется, хорошо работают для меня.

    public static T FindOrCreate<T>(this Table<T> table, Func<T, bool> find, Action<T> create) where T : class, new()
    {
        T val = table.FirstOrDefault(find);
        if (val == null)
        {
            val = new T();
            create(val);
            table.InsertOnSubmit(val);
        }
        return val;
    }

    public static T FindOrCreate<T>(this Table<T> table, Func<T, bool> find) where T : class, new()
    {
        return FindOrCreate(table, find, a => { });
    }

И это используется так:

    var invoiceDb = ctx.Invoices.FindOrCreate(a => a.InvoicerId == InvoicerId &&
                                                     a.Number == invoiceNumber);
    invoiceDb.Number = invoiceNumber;

Или

    var invoiceDb = ctx.Invoices.FindOrCreate(a => a.InvoicerId == InvoicerId &&
                                                     a.Number == invoiceNumber,
                                              a => a.Number = invoiceNumber);
1 голос
/ 26 апреля 2009

Как насчет использования метода расширения следующим образом:

public static T FirstOrCreate<T>(this IEnumerable<T> source) where T : class, new()
{
    var result = source.FirstOrDefault();
    return result != null ? result : new T();
}

Если вы хотите, чтобы он мог принимать предикат, вы можете использовать это определение:

public static T FirstOrCreate<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate) where T : class, new()
{
    var result = source.FirstOrDefault(predicate);
    return result != null ? result : new T();
}

Таким образом, вы можете использовать его вместо FirstOrDefault () следующим образом:

Invoice selectedInvoice = (from i in Invoices
                           where i.ID == invoiceID
                           select i).FirstOrCreate();

.. или с использованием предиката:

Invoice selectedInvoice = db.Invoices.FirstOrCreate(i => i.ID == invoiceID);

Вместо этого будет возвращать соответствующий объект или новый (не нулевой) объект.

Редактировать: я думал об этом сегодня, и мне пришло в голову, что вышеизложенное потребует от вас обнаружить, что объект является новым (не существует), и присоединить его к DataContext, поэтому я пришел к этому компромиссу , используя тот же подход:

public static T FirstOrCreate<T>(this IEnumerable<T> source, DataClassesDataContext db) where T : class, new()
{
    var result = source.FirstOrDefault();
    if (result == null)
    {
        result = new T();
        db.GetTable<T>().InsertOnSubmit(result);
    }
    return result;
}

Недостатком является то, что вы должны передавать DataContext в качестве параметра, но он должен работать достаточно хорошо:

Customer selectedCustomer = (from c in db.Customers
                             where c.CustomerId == selectedCustomerId
                             select c).FirstOrCreate(db);

Конечно, есть одно возражение? :)

0 голосов
/ 24 апреля 2009

Вы можете использовать Оператор нулирования (??)

var invoice = ctx.Invoices.SingleOrDefault(a => a.InvoicerId == InvoicerId &&
                                             a.Number == invoiceNumber) ??
                          new Invoice();
0 голосов
/ 24 апреля 2009

Может быть сокращено до.

if(invoiceDb == null) ctx.Invoices.InsertOnSubmit(invoiceDB = new Invoice() {Number = invoiceNumber});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...