У меня есть база данных PostgreSql 9.04, которая содержит реализацию postgres базы данных ASPNet Membership Services.Эта реализация находится в той же базе данных, что и мои собственные таблицы, но в другой схеме, называемой «безопасность».
По деловым причинам я включил таблицы aspnet_Users, aspnet_Membership и aspnet_Profiles в мою модель сущности.Ниже приведен DDL для этих таблиц.
CREATE TABLE security.aspnet_users (
userid UUID NOT NULL,
applicationname VARCHAR(255) NOT NULL,
username VARCHAR(255),
lastactivitydate TIMESTAMP,
isanonymous INT,
CONSTRAINT aspnet_users_userid_pk PRIMARY KEY (userid),
CONSTRAINT aspnet_users_username_pk UNIQUE (username, applicationname)
);
CREATE TABLE security.aspnet_membership (
userid UUID NOT NULL,
password VARCHAR(255),
passwordsalt VARCHAR(255),
passwordformat INT,
email VARCHAR(255),
passwordquestion VARCHAR(255),
passwordanswer VARCHAR(255),
comments VARCHAR(255),
isapproved INT,
islockedout INT,
creationdate TIMESTAMP,
lastlogindate TIMESTAMP,
lastpasswordchangeddate TIMESTAMP,
lastlockoutdate TIMESTAMP,
failedpasswordattemptcount INT,
failedpasswordattemptstart TIMESTAMP,
failedpasswordanswercount INT,
failedpasswordanswerstart TIMESTAMP,
CONSTRAINT aspnet_membership_userid_pk PRIMARY KEY (userid),
CONSTRAINT aspnet_membership_userid_ref FOREIGN KEY (userid) REFERENCES security.aspnet_users (userid)
);
CREATE TABLE security.aspnet_profiles (
userid UUID,
propertynames BYTEA NOT NULL,
propertyvaluesstring BYTEA NOT NULL,
propertyvaluesbinary BYTEA NULL,
lastupdateddate TIMESTAMP NOT NULL,
CONSTRAINT aspnet_profiles_userid_ref FOREIGN KEY (userid) REFERENCES security.aspnet_users (userid),
CONSTRAINT aspnet_profiles_userid_key UNIQUE (userid)
);
Опять же, это единственные таблицы из этой схемы, которые есть в моей модели.
Теперь, когда я вставляю строку в эти таблицы,и я вызываю SaveChanges, я получаю следующее сообщение об ошибке:
Невозможно определить основной конец отношения 'Membership_Users'.Несколько добавленных объектов могут иметь один и тот же первичный ключ.
Ниже приведен пример кода, который я использую для вставки новой или обновления существующей строки.Это репрезентативно для всего, что я делаю в отношении обновления базы данных.
public static void SaveUserProfile( CarSystemEntities context, UserProfileData data ) {
if ( context == null )
throw new ArgumentNullException( "context", "You must pass a non-null CarSystemEntities instance." );
if ( data == null )
throw new ArgumentNullException( "data", "You must pass a non-null UserProfileData instance." );
try {
Profile profile = null;
if ( !context.Profiles.Any( p => p.Userid == data.ID ) ) {
profile = new CarSystem.Profile{
LastUpdatedDate = data.LastUpdatedDate.LocalDateTime,
PropertyNames = data.PropertyNames,
PropertyValuesBinary = data.PropertyValuesBinary,
PropertyValuesString = data.PropertyValuesString,
Userid = data.ID
};
context.Profiles.AddObject( profile );
} else {
profile = QueryUerProfiles( context ).Where( p => p.Userid == data.ID ).Single();
if ( profile.LastUpdatedDate != data.LastUpdatedDate ) profile.LastUpdatedDate = data.LastUpdatedDate.LocalDateTime;
if ( profile.PropertyNames != data.PropertyNames ) profile.PropertyNames = data.PropertyNames;
if ( profile.PropertyValuesBinary != data.PropertyValuesBinary ) profile.PropertyValuesBinary = data.PropertyValuesBinary;
if ( profile.PropertyValuesString != data.PropertyValuesString ) profile.PropertyValuesString = data.PropertyValuesString;
}
} catch ( Exception ex ) {
throw new DataAccessException( DataAccessOperation.SaveProfile, FailureReason.DatabaseError, ex );
}
}
В чем причина этой ошибки?Как это исправить?
Спасибо
Тони
PS
При дальнейшем исследовании проблема заключается не в вставке строки, а в попыткеобновить строку в той же транзакции, в которой была вставлена строка.
По существу, существует очередь объектов для записи в базу данных.Каждый объект по очереди удаляется из очереди, и для сохранения его в нужной таблице вызывается метод, подобный приведенному выше.
При первом обращении к определенному идентификатору метод вставляет его.То есть проверка Any возвращает false.Код создает новый объект сущности и вызывает метод AddObject для набора сущностей, который соответствует таблице.Все идет нормально.
После этого предполагается, что проверка Any вернет true, указывая, что в ней уже есть строка с заданным идентификатором.Затем предполагается обновить строку.Но похоже, что проверка Any также возвращает false во второй раз, хотя я и вызвал AddObject для набора Entity, который соответствует таблице при первом вызове.
Есть идеи, что я делаю неправильно?
PPS
Я провел еще несколько тестов с открытым монитором Sql.Мы используем Devart dotConnect для библиотеки PostgreSql, и у них есть инструмент, который вы можете загрузить, который называется DbMonitor.Это позволяет вам отслеживать SQL, который испускается и выполняется Entity Framework.
Оказывается (как и следовало ожидать), что вызовы .Any выполняются как запросы к базе данных сразу, а всеиз вставок ставятся в очередь и применяются после вызова SaveChanges.Вызовы Any, похоже, не принимают никаких строк, ожидающих вставки в учет, только то, что возвращают вызовы базы данных.Поскольку вставляемые строки еще не вставлены, этот запрос всегда будет возвращать значение false, пока не будет вызван SaveChanges.
В результате моя логика в ее нынешнем виде не будет работать.Когда строка, ожидающая вставки, обновляется (то есть она появляется во второй раз в очереди), логика вставки запускается во второй раз.Иногда я получаю исключение, указывающее, что ограничение уникального или первичного ключа нарушается, в других случаях я получаю сообщение, о котором я первоначально разместил сообщение.
Мне нужно, чтобы все вставки и обновления выполнялись водна транзакция, и мне нужно, чтобы вставки происходили в базе данных во время вызова AddObject.Тем не менее, мне по-прежнему нужны все вставки и обновления для отката, если что-то идет не так, вставка или обновление одной строки, или если в коде C # возникает какая-то другая ошибка.
У кого-нибудь есть идеи, как мне это сделатьEntity Framework?