Сведения о вопросе

Life

19:07, 14th August, 2020

Теги

c#   linq   repository    

LINQ, сущность, реализующая интерфейс и исключение в сопоставлении

Просмотров: 509   Ответов: 4

Я использую шаблон репозитория с LINQ, есть IRepository.DeleteOnSubmit(T сущности). Он отлично работает, но когда мой класс сущностей имеет интерфейс, например:

public interface IEntity { int ID {get;set;} }

public partial class MyEntity: IEntity {

    public int ID { 
        get { return this.IDfield; }
        set { this.IDfield=value;  }
    }
}

а затем пытается удалить какой-то объект, как это:

IEntity ie=repository.GetByID(1);
repoitory.DeleteOnSubmit(ie);

бросает
Член 'IEntity.ID' не имеет поддерживаемого перевода в SQL.

извлечение данных из DB работает, но удалить и вставить не. Как использовать интерфейс против DataContext?


Вот оно:
Сообщение об исключении: Член 'MMRI.DAL.ITag.idContent' не имеет поддерживаемого перевода в SQL.

Код:

var d = repContent.GetAll().Where(x => x.idContent.Equals(idContent));
foreach (var tagConnect in d)    <- error line
{
    repContet.DeleteOnSubmit(tagConnect);

(он получает все теги из DB и удаляет их)

И стек trace:

[NotSupportedException: The member 'MMRI.DAL.ITag.idContent' has no supported translation to SQL.]
   System.Data.Linq.SqlClient.Visitor.VisitMember(SqlMember m) +621763
   System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +541
   System.Data.Linq.SqlClient.SqlVisitor.VisitExpression(SqlExpression exp) +8
   System.Data.Linq.SqlClient.SqlVisitor.VisitBinaryOperator(SqlBinary bo) +18
   System.Data.Linq.SqlClient.Visitor.VisitBinaryOperator(SqlBinary bo) +18
   System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +196
   System.Data.Linq.SqlClient.SqlVisitor.VisitExpression(SqlExpression exp) +8
   System.Data.Linq.SqlClient.SqlVisitor.VisitSelectCore(SqlSelect select) +46
   System.Data.Linq.SqlClient.Visitor.VisitSelect(SqlSelect select) +20
   System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) +1024
   System.Data.Linq.SqlClient.SqlProvider.BuildQuery( ...

Когда я пытаюсь сделать украсить частичный класс:

[Column(Storage = "_idEvent", DbType = "Int NOT NULL", IsPrimaryKey = true)]
public int idContent
{ get { return this.idEvent; } set { this.idEvent=value; } }

он выдает ошибку "недопустимое имя столбца 'idContent'."



  Сведения об ответе

COOL

07:31, 17th August, 2020

Похоже, Microsoft отказалась от поддержки оператора == в интерфейсах при использовании linq-to-sql в MVC4 (или, возможно, он никогда не поддерживался). Однако вместо оператора == можно использовать i.ID.Equals(someId) .

Литье от IQueryable до IEnumerable работает, но не должно использоваться! Причина в том, что IQueryable имеет фанк-реализацию IEnumerable . Независимо от того, какой метод linq вы будете использовать на IQueryable через интерфейс IEnumerable , сначала будет выполнен запрос, все результаты будут извлечены в память из DB и в конечном итоге будут запущены локально на данных (обычно эти методы будут переведены в SQL и выполнены в DB). Представьте, что вы пытаетесь получить одну строку из таблицы, содержащей миллиард строк, извлекая все из них только для выбора одного (и это становится намного хуже с небрежным приведением IQueryable к IEnumerable и ленивой загрузкой связанных данных).

По-видимому, у Linq нет проблем с использованием оператора == с интерфейсами на локальных данных (поэтому затрагивается только IQueryable ), а также с Entity Framework (или так я слышал).


  Сведения об ответе

crush

19:15, 26th August, 2020

Это работает для меня -

public partial class MyEntity: IEntity 
 {    [Column(Name = "IDfield", Storage = "_IDfield", IsDbGenerated = true)]
      public int ID 
       {         
          get { return this.IDfield; }        
          set { this.IDfield=value;  }    
       } 
 }


  Сведения об ответе

baggs

18:45, 27th August, 2020

Для перевода вашего запроса LINQ в фактический SQL, Linq2SQL проверяет выражение, которое вы ему даете. Проблема заключается в том, что вы не предоставили достаточно информации для L2S, чтобы иметь возможность перевести свойство "ID" в фактическое имя столбца DB. Вы можете добиться желаемого, убедившись, что L2S может сопоставить "ID" с "IDField".

Это должно быть возможно с использованием подхода, изложенного в ответах.

Если вы используете конструктор, вы также можете просто переименовать свойство класса "IDField" в "ID", с дополнительным преимуществом, что вам больше не придется явно реализовывать свойство "ID" в своем частичном классе, т. е. определение частичного класса для MyEntity просто становится:

public partial class MyEntity: IEntity 
{    
}


  Сведения об ответе

baggs

12:32, 4th August, 2020

Попробовать это:

using System.Data.Linq.Mapping;

public partial class MyEntity: IEntity 
 {    [Column(Storage="IDfield", DbType="int not null", IsPrimaryKey=true)]
      public int ID 
       {         
          get { return this.IDfield; }        
          set { this.IDfield=value;  }    
       } 
 }


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться