2016-11-08 3 views
2

У меня есть различные методы, которые должны иметь возможность вызвать общий метод, передающий DbSet в качестве параметра. На данный момент у меня есть этот рабочий код (здесь упрощенно):C# generics для DbSet <something>

public class MyClass 
{ 
    private async Task<JsonResult> Delete<T>(int? id, T dbs) where T : DbSet<A> 
    { 
     var row = await dbs.SingleOrDefaultAsync(m => m.ID == id); 
     dbs.Remove(row); 
     await db.SaveChangesAsync(); 
     return Json(r); // definition od "r" removed from code to simplify it 
    } 

    public async Task<JsonResult> A(int? id) 
    { 
     return await Delete(id, db.A); 
    } 

    public async Task<JsonResult> B(int? id) 
    { 
     return await Delete(id, db.B); 
    } 

    public async Task<JsonResult> C(int? id) 
    { 
     return await Delete(id, db.C); 
    } 

Я не знаю, горячей, чтобы изменить подпись метода «Удалить», так что методы A, B, C ... все это может назвать это ,

+0

Не уверен, что вы хотите передать 'DbSet', может быть, проще вызвать метод' context.Set '? – DavidG

+0

Не связано с вашим вопросом, но каковы методы 'Delete', которые должны точно выполнять? Кажется, что удаляет элемент из 'DbSet ', полученный в качестве аргумента, а затем сохраняет изменения в полностью несвязанный контекст. –

+0

Удаляет элемент из DbSet, соответствующий принятому «id». – Marko

ответ

4

Поскольку вы ссылаетесь поле идентификатора в вашем Delete, вам нужно ввести некоторый интерфейс, как

interface IHasID { 
    int ID { get; } 
} 

Тогда вам нужно реализовать этот интерфейс (в частичном классе) для всех субъектов с идентификатором. После этого вы можете изменить ваш Удалить как этот

private async Task<JsonResult> Delete<T>(int? id, DbSet<T> dbs) where T : class, IHasID {    
    var row = await dbs.SingleOrDefaultAsync(m => m.ID == id); 
    dbs.Remove(row); 
    await db.SaveChangesAsync(); 
    return Json(r); // definition od "r" removed from code to simplify it 
} 

И использовать, как это (при условии, реализует IHasID):

public async Task<JsonResult> A(int? id) { 
    return await Delete(id, db.As); 
} 

Если вы не хотите, чтобы реализовать IHasID для каждого объекта (хотя это очень легко , поскольку свойство ID уже существует в ваших сущностях), можно обойтись без интерфейса (хотя и менее безопасно, потому что вы сможете передать любой объект этому методу Delete, и вы не найдете ошибку до времени выполнения):

private async Task<JsonResult> Delete<T>(int? id, DbSet<T> dbs) where T : class 
{ 
    var parameter = Expression.Parameter(typeof(T), "entity"); 
    // generate expression entity => entity.ID = id 
    var condition = (Expression<Func<T, bool>>) Expression.Lambda(
      Expression.Equal(
       Expression.Property(parameter, "ID"), 
       Expression.Constant(id) 
      ) 
     , parameter); 

    var row = await dbs.SingleOrDefaultAsync(condition); 
    dbs.Remove(row); 
    await db.SaveChangesAsync(); 
    return Json(r); 
} 
+0

Мне удалось добраться до 'private async Task Удалить (int? Id, DbSet dbs) где T: class' и застрял в проблеме' ID'. Поэтому я применил ваши предложения, создал интерфейс и добавил его в класс 'A', а затем в общую подпись метода. Но копирайтер все еще жалуется: Тип «А» не может использоваться как параметр типа «Т» в родовом типе или методе «Удалить (int ?, DbSet )». Нет никакого неявного преобразования ссылок с 'A' на 'IHasID'. – Marko

+0

Вы можете лучше разместить свой код полностью. Код из моего ответа, который я тестировал и проверял, работает, как и ожидалось. Хотя ошибка предполагает, что тип A по-прежнему не реализует IHasID. – Evk

+0

Извините, я допустил ошибку в копировании кода интерфейса в двух пространствах имен, не осознавая этого. Я подтверждаю, что ваш код работает хорошо. ** Спасибо! ** – Marko

Смежные вопросы