LINQ to SQL - - PullRequest
       77

LINQ to SQL -

5 голосов
/ 26 октября 2008

Я пытаюсь использовать LINQ для вставки записи в дочернюю таблицу, и я получение ошибки «Указанное приведение неверно», в которой есть что ключи задействованы. Трассировка стека:

Сообщение: указанное приведение недействительно.

Тип: System.InvalidCastException Источник: System.Data.Linq TargetSite: логический TryCreateKeyFromValues ​​(System.Object [], V ByRef) HelpLink: ноль Стек: в System.Data.Linq.IdentityManager.StandardIdentityManager.SingleKeyManager 2.TryCreateKeyFromValues(Object[] values, V& v) at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache 2.Find (Object [] keyValues) в System.Data.Linq.IdentityManager.StandardIdentityManager.Find (метатип тип, Object [] keyValues) в System.Data.Linq.CommonDataServices.GetCachedObject (метатип тип, Object [] keyValues) в System.Data.Linq.ChangeProcessor.GetOtherItem (MetaAssociation Assoc, экземпляр объекта) в System.Data.Linq.ChangeProcessor.BuildEdgeMaps () в System.Data.Linq.ChangeProcessor.SubmitChanges (ConflictMode faultMode) в System.Data.Linq.DataContext.SubmitChanges (ConflictMode faultMode) в System.Data.Linq.DataContext.SubmitChanges ()

(.....)

Эта ошибка выдается на следующий код:

 ResponseDataContext db = new ResponseDataContext(m_ConnectionString);
 CodebookVersion codebookVersion = db.CodebookVersions.Single(cv => cv.VersionTag == m_CodebookVersionTag);
 ResponseCode rc = new ResponseCode()
    {
       SurveyQuestionName = "Q11",
       Code = 3,
       Description = "Yet another code"
    };
 codebookVersion.ResponseCodes.Add(rc);
 db.SubmitChanges(); //exception gets thrown here

Указанные таблицы имеют отношения FK между двумя из них.
Столбец родительской таблицы называется id, является PK и имеет тип: INT NOT NULL IDENTITY
Столбец дочерней таблицы называется responseCodeTableId и имеет тип: INT NOT NULL.

codebookVersion (родительский класс) отображается в таблицу tblResponseCodeTable
responseCode (childClass) сопоставляется с таблицей tblResponseCode

Если я выполняю SQL напрямую, это работает. например

INSERT INTO tblResponseCode 
(responseCodeTableId, surveyQuestionName, code, description)
VALUES (13683, 'Q11', 3, 'Yet another code')

Обновления для того же класса работают правильно. например

codebookVersion.ResponseCodes[0].Description = "BlahBlahBlah";
db.SubmitChanges(); //no exception - change is committed to db

Я изучил переменную rc после операции .Add (), и она действительно получает правильный responseCodeTableId, как я и ожидал, поскольку добавляю ее в эту коллекцию.

tblResponseCodeTable's full definition:
COLUMN_NAME TYPE_NAME
id                  int identity
responseCodeTableId int
surveyQuestionName  nvarchar
code                smallint
description         nvarchar
dtCreate            smalldatetime

dtCreate имеет значение по умолчанию GetDate ().

Единственная полезная информация, о которой я могу подумать, это отсутствие SQL когда-либо пробовал против базы данных, поэтому LINQ взрывается, прежде чем когда-либо пытается (следовательно, ошибка не является SqlException). Я профилирован и проверен что не делается никаких попыток выполнить какие-либо операторы в базе данных.

Я прочитал и увидел проблему, когда у вас есть отношение к не-PK-полю, но это не подходит для моего случая.

Может ли кто-нибудь пролить свет на эту ситуацию для меня? Какую невероятно очевидную вещь я здесь упускаю?

Большое спасибо.
Пол Преуветт

Ответы [ 14 ]

1 голос
/ 26 октября 2008

Поскольку база данных не вызывается, я думаю, что вам нужно посмотреть на отображения, которые использует linq для sql. Как выглядит Ассоциация? Должна быть ассоциация как на родительском, так и на дочернем классах. Посмотрите на связь linq to sql между двумя классами. Ассоциация должна иметь свойство ThisKey. Я думаю, что приведение, которое не выполняется, пытается привести значение свойства, на которое указывает ThisKey. Насколько я могу судить, может быть проблема, когда существует более одного ключа, а тип первого ключа не совпадает с типом, на который указывает ThisKey. Я не уверен, как linq определит, какой первый ключ. Судя по всему, у вас есть только один ключ и один внешний ключ, так что это не должно быть проблемой, но дизайнер, если вы его используете, как известно, проявил творческий подход. Я в основном догадываюсь, но это похоже на то, что я видел раньше.

1 голос
/ 04 июня 2009

Является ли это примером этой ошибки ? Если это так, попробуйте запустить свой код в .NET 4.0 сейчас, когда бета-версия отсутствует.

Если, как и я, вы не готовы начать использовать бета-версию, возможно, вы сможете обойти эту проблему. Кажется, проблема в том, что LINQ не поддерживает должным образом отношения, определенные для полей не первичного ключа. Однако термин «первичный ключ» относится не к первичному ключу, определенному в таблице SQL, а к первичному ключу, определенному в конструкторе LINQ.

Если вы перетащили свои таблицы в конструктор, Visual Studio автоматически проверяет первичный ключ, определенный в базе данных, и помечает соответствующие поля класса как «первичные ключи». Однако они не должны соответствовать друг другу. Вы можете удалить ключ, выбранный Visual Studio, и выбрать другое поле (или группу полей). Конечно, вы должны убедиться, что это логично (у вас должно быть уникальное ограничение в базе данных для выбранного вами поля / полей).

Итак, у меня было 2 таблицы / классы, связанные друг с другом с использованием альтернативного ключа. В родительской таблице было 2 ключа: суррогатный первичный ключ, определенный как int, и альтернативный естественный ключ, определенный как строка. В конструкторе LINQ я определил ассоциацию, используя альтернативный ключ, и я испытывал исключение InvalidCastException при попытке обновить это поле ассоциации в дочернем объекте. Чтобы обойти это, я пошел в дизайнер LINQ, выбрал int, а затем изменил свойство Primary Key с True на False. Затем я выбрал строку и установил для ее свойства Primary Key значение True. Перекомпилировано, повторно протестировано, исключение InvalidCastException.

Глядя на снимок экрана, вы можете решить проблему, изменив первичный ключ LINQ на ResponseCode с ResponseCode.ID на ResponseCode.ResponseCodeTableID

1 голос
/ 26 октября 2008

Разместите схему родительской таблицы.

если вы посмотрите здесь, у некоторых других была ваша проблема. http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3493504&SiteID=1

Похоже, что Linq2SQL имеет проблемы с отображением некоторых внешних ключей на некоторые первичные ключи. У одного парня было разрешение, но я думаю, что вы уже отображаете столбец IDENTITY.

0 голосов
/ 16 сентября 2009

У нас была похожая проблема, вызванная использованием нецелых ключей. Подробности и номер исправления здесь: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=351358

0 голосов
/ 18 февраля 2009

Где-то в вашем графе объектов произошла ошибка преобразования, базовая модель данных (или модель Linq To SQL) изменилась. Обычно это что-то вроде NVARCHAR (1) -> CHAR, когда оно должно быть STRING, или что-то подобное.

Эта ошибка не очень интересна, надеюсь, ваша объектная модель мала.

0 голосов
/ 24 ноября 2008

Я столкнулся с очень похожей проблемой. Я свяжу вас с моим многословным постом: http://forums.asp.net/p/1223080/2763049.aspx

И я также предложу решение, просто предположение ...

    ResponseDataContext db = new ResponseDataContext(m_ConnectionString);
    CodebookVersion codebookVersion = db.CodebookVersions.Single(cv => cv.VersionTag == m_CodebookVersionTag); 
    ResponseCode rc = new ResponseCode()
    {   
        ResponseCodeTableId = codebookVersion.Id,   
        SurveyQuestionName = "Q11",   
        Code = 3,   
        Description = "Yet another code"
    };
    db.ResponseCodes.InsertOnSubmit(rc);
    db.SubmitChanges();
0 голосов
/ 03 ноября 2008
0 голосов
/ 03 ноября 2008

Вы можете проверить, чтобы увидеть, что любые поля в таблицах вашей базы данных, которые устанавливаются сервером БД при вставке новой записи, отражают это на диаграмме Linq to SQL. Если вы выберете поле на диаграмме Linq to SQL и просмотрите его свойства, вы увидите поле с именем «Auto Generated Value», которое при значении true гарантирует, что все новые записи получат значение по умолчанию, указанное в базе данных.

0 голосов
/ 26 октября 2008
ResponseCode rc = new ResponseCode()
{
   CodebookVersion = codebookVersion,
   SurveyQuestionName = "Q11",
   Code = 3,
   Description = "Yet another code"
};
db.ResponseCodes.InsertOnSubmit(rc);
db.SubmitChanges();
0 голосов
/ 26 октября 2008

Майк, я тебя слышу. Но куда бы я ни посмотрел, все выглядит правильно. Я проверил и перепроверил, что ResponseTableId - это int, а Id - это int. Они определены как таковые в конструкторе, и когда я смотрю на сгенерированный код, все снова оказывается в порядке.

Я изучил ассоциации. Вот они:

[Table(Name="dbo.tblResponseCode")]
public partial class ResponseCode : ...
    ...
   [Association(Name="CodebookVersion_tblResponseCode", Storage="_CodebookVersion", ThisKey="ResponseCodeTableId", OtherKey="Id", IsForeignKey=true)]
   public CodebookVersion CodebookVersion
   {
      ...
   }

[Table(Name="dbo.tblResponseCodeTable")]
    public partial class CodebookVersion : ...
    ...
   [Association(Name="CodebookVersion_tblResponseCode", Storage="_ResponseCodes", ThisKey="Id", OtherKey="ResponseCodeTableId")]
   public EntitySet<ResponseCode> ResponseCodes
   {
      ...
   }

И скриншот ассоциации на случай, если это поможет:
designer

Есть еще мысли?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...