EF Core SQLITE - ошибка SQLite 19: «Сбой уникального ограничения - PullRequest
0 голосов
/ 09 октября 2018

Я изучаю ядро ​​Entity Framework, используя его вместе с SQLITE. У меня есть 2 таблицы в базе данных.

Сообщения:

CREATE TABLE `Messages` (
    `Id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    `IsDeleted` INTEGER NOT NULL,
    `FromUserId`    INTEGER,
    `ToUserId`  INTEGER,
    `SendDate`  TEXT NOT NULL,
    `ReadDate`  TEXT NOT NULL,
    `MessageContent`    TEXT,
    CONSTRAINT `FK_Messages_Users_ToUserId` FOREIGN KEY(`ToUserId`) REFERENCES `Users`(`Id`) ON DELETE RESTRICT,
    CONSTRAINT `FK_Messages_Users_FromUserId` FOREIGN KEY(`FromUserId`) REFERENCES `Users`(`Id`) ON DELETE RESTRICT
);

и Таблица пользователей:

CREATE TABLE `Users` (
    `Id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    `IsDeleted` INTEGER NOT NULL,
    `Name`  TEXT,
    `DisplayName`   TEXT,
    `Gender`    INTEGER NOT NULL,
    `BirthDate` TEXT NOT NULL
);

мои классы c # выглядят так:

public class User
{
    public int Id {get;set;}
    public bool IsDeleted{get;set;}
    [Required]
    public string Name{get;set;}

    public string DisplayName{get;set;}

    [Required]
    public char Gender{get;set;}

    [Required]
    public DateTime BirthDate{get;set;}

    public User(string n, string dn, char g, DateTime bd)
    {
        Name=n; DisplayName = dn; Gender = g; BirthDate = bd;
    }

    protected User(){}

    public override string ToString()
    {
        return string.Format("{0} ({1}) {2}", this.Name, this.Gender,this.BirthDate.ToShortDateString());
    }
}

и класс Messages:

public class Message 
{
    public int Id{get;set;}
    public bool IsDeleted{get;set;}
    [Required]
    public Users.User FromUser{get;set;}

    [Required]
    public Users.User ToUser{get;set;}

    [Required]
    public DateTime SendDate{get;set;}
    public DateTime? ReadDate{get;set;}

    [Required]
    public string MessageContent{get;set;}

    protected Message(){}

    public Message(User from, User to, string content)
    {
        this.FromUser = from;
        this.ToUser = to;
        this.MessageContent = content;
        this.SendDate = DateTime.Now;
        this.ReadDate = DateTime.Now;
    }

}

таблица пользователей работает, но когда я пытаюсь добавить новую сущность к сообщениям следующим образом:

public override int Insert(Message entity)
{
    dbc.Messages.Add(entity);
    dbc.SaveChanges();
    return entity.Id;
}

Я получаю следующую ошибку:

Ошибка SQLite 19: 'Не удалось выполнить ограничение UNIQUE

Понятия не имею, что не так.Когда я вручную вставляю данные в базу данных (используя браузер БД для sqlite), это работает.В порядке ли отношения в классах?

Мой dbContextSnapshot:

[DbContext(typeof(RandevouDbContext))]
partial class RandevouDbContextModelSnapshot : ModelSnapshot
{
    protected override void BuildModel(ModelBuilder modelBuilder)
    {
#pragma warning disable 612, 618
    modelBuilder.HasAnnotation("ProductVersion", "2.1.4-rtm-31024");

    modelBuilder.Entity("RandevouData.Messages.Message", b =>
        {
            b.Property<int>("Id")
                .ValueGeneratedOnAdd();

            b.Property<int>("FromUserId");

            b.Property<bool>("IsDeleted");

            b.Property<string>("MessageContent")
                .IsRequired();

            b.Property<DateTime?>("ReadDate");

            b.Property<DateTime>("SendDate");

            b.Property<int>("ToUserId");

            b.HasKey("Id");

            b.HasIndex("FromUserId");

            b.HasIndex("ToUserId");

            b.ToTable("Messages");
        });

    modelBuilder.Entity("RandevouData.Users.User", b =>
        {
            b.Property<int>("Id")
                .ValueGeneratedOnAdd();

            b.Property<DateTime>("BirthDate");

            b.Property<string>("DisplayName");

            b.Property<char>("Gender");

            b.Property<bool>("IsDeleted");

            b.Property<string>("Name")
                .IsRequired();

            b.HasKey("Id");

            b.ToTable("Users");
        });

    modelBuilder.Entity("RandevouData.Messages.Message", b =>
        {
            b.HasOne("RandevouData.Users.User", "FromUser")
                .WithMany()
                .HasForeignKey("FromUserId")
                .OnDelete(DeleteBehavior.Cascade);

            b.HasOne("RandevouData.Users.User", "ToUser")
                .WithMany()
                .HasForeignKey("ToUserId")
                .OnDelete(DeleteBehavior.Cascade);
        });
#pragma warning restore 612, 618
}

Кстати.Я не могу настроить сопоставление с двух сторон.

Сущность Message имеет поля UserFrom и UserTo, но сущность User не может иметь сообщения, поскольку один раз он является userFrom, а другой - userTo.

И есть также код, где я создаю сущность Message

        public int SendMessage(int senderId, int receiverId, string content)
    {
        var dao = new MessagesDao();
        var usersDao = new UsersDao();
        var userService = new UserService(mapper);

        var sender = usersDao.Get(senderId);
        var receiver = usersDao.Get(receiverId);

        var entity = new Message(sender,receiver,content);
        var id = dao.Insert(entity);
        return id;
    }

user dao, где я переопределяю метод GET

 public override User Get(int id)
        {
            using (var context = new RandevouDbContext())
            { 
                var user = dbc.Find<User>(id);
                return user;
            }
        }

и MessagesDao, где я переопределяю метод Add

 public override int Insert(Message entity)
        {
            using (var dc = new RandevouDbContext())
            {
                dc.Messages.Add(entity);
                dc.SaveChanges();
                return entity.Id;
            }
        }

Кстати, я не знаю, все ли в порядке, но у меня 0 записей для обновления (!?) enter image description here

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Хорошо, я решил проблемы.Прочитайте некоторые статьи об EF DbContext.Когда я использовал два других контекста для GET User и CREATE message, сущности (user1 и user2) не были теми же сущностями, которые я использовал для второго контекста.Я имею в виду, что эти объекты были такими же, но у них было другое отслеживание

EF Core / Sqlite Отношение один-ко-многим не удалось на уникальном индексе Ограничение

Итак, я решилпроблема с использованием одного контекста для одной бизнес-транзакции (не одной транзакции базы данных).Просто перенес создание контекста в бизнес-логику, и класс дао Generic ожидал контекст в конструкторе, например:

public class MessagesDao : BasicDao<Message>
    {
        public MessagesDao(RandevouDbContext dbc) : base(dbc)
        {

        }
        public IQueryable<Message> QueryMessages()
        {
                return dbc.Messages.AsQueryable();

        }

        public override int Insert(Message entity)
        {
            dbc.Messages.Add(entity);
            dbc.SaveChanges();
            return entity.Id;

        }
    }



 public abstract class BasicDao<TEntity> where TEntity : BasicRandevouObject
    {
        protected RandevouDbContext dbc;
        public BasicDao(RandevouDbContext dbc) { this.dbc = dbc; }

        public virtual int Insert(TEntity entity)
        {
                dbc.Add<TEntity>(entity);
                dbc.SaveChanges();
                return entity.Id;

        }

        public virtual void Update(TEntity entity)
        {
                dbc.Update(entity);
                dbc.SaveChanges();

        }

        public virtual void Delete(TEntity entity)
        {
                dbc.Remove(entity);
                dbc.SaveChanges();

        }

        public virtual TEntity Get(int id)
        {
                var entity = dbc.Find<TEntity>(id);
                return entity;

        }


    }

и в коде бизнес-логики:

public int SendMessage(int senderId, int receiverId, string content)
        {
            using (var dbc = new RandevouDbContext())
            { 
                var dao = new MessagesDao(dbc);
            var usersDao = new UsersDao(dbc);
            var userService = new UserService(mapper);

            var sender = usersDao.Get(senderId);
            var receiver = usersDao.Get(receiverId);

            var entity = new Message(sender,receiver,content);
            var id = dao.Insert(entity);
            return id;
            }
        }

теперь всеработает.Кстати, это все еще грязный код, потому что я просто пробую кое-что, но я надеюсь, что если у кого-то возникнут похожие проблемы, он найдет этот пост.

0 голосов
/ 09 октября 2018

Чего не хватает в вашем (очень подробном) вопросе, так это состав Message, который вы передаете Insert().Вы ранее сохранили два User s в базе данных, или это тоже два новых объекта?Если они являются новыми, то их ID должен быть нулевым, чтобы EF знал, что их нужно создать, прежде чем создавать Message.

Кстати, извинения, это скорее «ответ», чем комментарий- Странные правила S / O означают, что у меня недостаточно репутации, чтобы добавить комментарий ...

...