Я создал полную привязку EF к одной из наших баз данных (структуру которой я не контролирую) для выполнения некоторых базовых операций CRUD. Пока все идет хорошо. Однако у меня возникла проблема со вставкой одного из моих классов. Он пытается вставить новую запись в таблицу под названием «applmort». Я не буду вдаваться в подробности того, как устроена эта таблица базы данных, поскольку ее создает не моя компания. Но у нас есть к нему доступ и мы можем выполнять с ним операции CRUD.
В этой таблице есть столбец, который я назову UWT
, который объявлен как varchar(12)
. Итак, я настроил конфигурацию EF, чтобы ограничить входящие в нее значения до 12. Вы заметите это в файле конфигурации, который я опубликую. Пока в столбце стоит NOTNULL
, я могу просто поставить в столбец пробел varchar
и всё в порядке. Никаких ограничений по таблице для этого нет.
Итак, когда я пытаюсь добавить новую запись, я не указываю это поле в объекте. Я могу сделать это с кучей других столбцов в таблице, и поскольку мой файл конфигурации указывает EF вставить строку. По умолчанию это пустая строка, все работает удобно. За исключением этой UWT
рубрики. Он отказывается и сообщает мне, что произошла ошибка усечения. Поскольку я ввожу пустую строку, это кажется странным. Я копаю и понимаю, что EF пытается создать этот столбец UWT
в качестве альтернативного ключа, а затем заполняет его случайным GUID, который я никогда не говорил ему использовать. Я отслеживаю это и обнаруживаю, что у меня есть еще одна таблица, подключенная к этой через файл конфигурации (это должен быть второй класс конфигурации, который я перечислил ниже). Этот другой объект связан с моим объектом Application через UWT
. Это должно быть нормально, и я не думал, что установка этого вызовет проблемы. Однако это так. Когда я удаляю «один ко многим» из второго объекта, чтобы разорвать ссылку, запись вставляется правильно.
Еще один обходной путь, который я нашел, заключался в том, чтобы указать столбец UWT
в объекте Application как пустую строку до того, как он достигнет значения по умолчанию в конфигурации. Это также позволяет без проблем вставить запись.
Я мог бы использовать любой из этих обходных путей. Второй будет работать лучше всего и позволит мне сохранить ссылку на таблицу. Но это кажется очень и очень странным. Этого не происходит ни с одной другой ссылкой на таблицу, которую я создаю, поэтому я должен спросить: я делаю здесь что-то не так? Я где-то установил что-то, из-за чего GUID помещается в явно не-GUID столбец? Я не могу, хоть убей, найти это.
public class Application
{
public DateTime? ChangeDate { get; set; }
public int ID { get; set; }
public DateTime? ApplicationDate { get; set; }
public string StructureID { get; set; } = null!;
public string UWT { get; set; } = null!;
public int UnitNumber { get; set; }
public virtual Structure Structure { get; set; } = null!;
public virtual ICollection<ApplicationHold> ApplicationHolds { get; set; } = [];
}
public class ApplicationHold
{
public DateTime? ChangeDate { get; set; }
public string UWT { get; set; } = null!;
public int ID { get; set; }
public virtual Application Application { get; set; } = null!;
}
public class ApplicationConfig : IEntityTypeConfiguration<Application>
{
public void Configure(EntityTypeBuilder<Application> entity)
{
entity.ToTable("applmort");
entity.HasKey(e => e.ID);
entity.Property(e => e.ChangeDate)
.HasColumnName("changedate")
.HasColumnType("datetime")
.HasDefaultValue(DateTime.Now)
.IsRequired();
entity.Property(e => e.ID)
.HasColumnName("id")
.UseIdentityColumn();
entity.Property(e => e.ApplicationDate)
.HasColumnName("appldate")
.HasColumnType("datetime")
.HasDefaultValue(DateTime.Now);
entity.Property(e => e.StructureID)
.HasColumnName("stru")
.HasMaxLength(3)
.HasDefaultValue(string.Empty)
.IsRequired();
entity.Property(e => e.UWT)
.HasColumnName("uwt")
.HasColumnType("varchar")
.HasMaxLength(12)
.HasDefaultValue(string.Empty)
.IsRequired();
entity.Property(e => e.UnitNumber)
.HasColumnName("units")
.HasColumnType("int")
.HasDefaultValue(0)
.IsRequired();
entity.HasOne(e => e.Structure).WithMany(e => e.Applications)
.HasForeignKey(e => e.LoanStructureID)
.HasPrincipalKey(e => e.LoanStructureID)
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
}
}
public class ApplicationHoldConfig : IEntityTypeConfiguration<ApplicationHold>
{
public void Configure(EntityTypeBuilder<ApplicationHold> entity)
{
entity.ToTable("applhold");
entity.HasKey(e => e.ID);
entity.Property(e => e.ChangeDate)
.HasColumnName("changedate")
.HasColumnType("datetime")
.HasDefaultValue(DateTime.Now)
.IsRequired();
entity.Property(e => e.ID)
.HasColumnName("id")
.UseIdentityColumn();
entity.Property(e => e.UWT)
.HasColumnName("uwt")
.HasColumnType("varchar")
.HasMaxLength(12)
.HasDefaultValue(string.Empty)
.IsRequired();
entity.HasOne(entity => entity.Application).WithMany(e => e.ApplicationHolds)
.HasForeignKey(entity => entity.UWT)
.HasPrincipalKey(e => e.UWT)
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
}
}
EF пытается создать уникальное ограничение для поля UWT, возможно, тем, как он понимает связь между Application и ApplicationHold.
Вы можете попробовать не использовать HasDefaultValue(string. Empty), так как кажется, что даже наличия этого кода достаточно, чтобы EF автоматически генерировал отношения, стирал конфигурации значений по умолчанию и обрабатывал их в своем приложении.
entity.Property(e => e.UWT)
.HasColumnName("uwt")
.HasColumnType("varchar")
.HasMaxLength(12)
.HasDefaultValue(string.Empty)
.IsRequired();
Установка этого значения напрямую должна решить проблему при вставке записи.
Application application = new()
{
UWT = string.Empty,
};
Да, кажется, это хорошее решение. Однако это все еще странно, поскольку у меня есть куча других ссылок на таблицы и строки. Пустой набор для множества других мест... почему именно это, остается загадкой. Но спасибо! Это хороший способ справиться с этим. Если кто-нибудь еще знает, ПОЧЕМУ это происходит... Я хотел бы знать.