【问题标题】:Cannot insert multiple items into SQLite database无法将多个项目插入 SQLite 数据库
【发布时间】:2015-07-06 17:47:14
【问题描述】:

数据库有一个批次数据的主表,每个批次可以有零个或多个样本。它们在 Batch.BatchID == Samples.FK_BatchID 上链接。这些表的类如下所示。

我可以向 Batches 添加一个值 - 自动增量 BatchID 会按预期更新。 我可以向 Samples 添加一个值。 我无法向 Samples 表添加多个值并获得异常

附加信息:无法使用已在使用的键添加实体。

如果我将 STOP 设置为“1”,则 db 将获得一个新批次,其中包含正确引用的新样本。我必须做什么才能允许为单个批次添加多个样品。此外,理想情况下,我希望使用相同的上下文和单个“SubmitChanges()”操作 - 但让我在跑步之前先走。

这是我尝试过的代码:

 Int64 newbatchID = 0;
 using (var context = new Data.BatchContext(connection))
 {    // This 'chunk' work fine and the newbatchID gets the new value
      context.Log = Console.Out;
      Data.Batches newBatch = new Data.Batches {
           Created = System.DateTime.Now.ToString("u"),
           Title = "New Title",
           Varietal = "Waltz"
      };

      // Return the Batch Id if necessary...
      var qs = from c in context.sqlite_sequence
               where c.name == "Batches"
               select c.seq;
      context.Batches.InsertOnSubmit(newBatch);
      context.SubmitChanges();
      newbatchID = qs.ToList().First();
 }

 // Use the new batch ID to submit a load of new samples
 int STOP = 2;     // PROBLEM. If Stop is not 1 the following fails
 using (var context = new Data.BatchContext(connection))
 {
      context.Log = Console.Out;
      List<Data.Samples> samplelist = new List<Data.Samples>();
      for (var i = 0; i < STOP; ++i)
      {    // Just to get different time values
           System.Threading.Thread.Sleep(500);
           samplelist.Add(
                new Data.Samples {
                     // Commenting out the FK_BatchID doesn't help
                     FK_BatchID = newbatchID,
                     Created = System.DateTime.Now.ToString("u"),
                     ImageURI = String.Format("./Path/Img_{0}.jpg", i)
                });
           }
           context.Samples.InsertAllOnSubmit(samplelist);
           context.SubmitChanges();
      }

数据库类

[Table(Name = "Batches")]
public class Batches
{
    public virtual ICollection<Batches> batches { get; set; }
    public Batches()
    {
        batches = new HashSet<Batches>();
    }

    // Primary key - nullable to allow Autoincrement
    [Column(Name = "BatchID", IsPrimaryKey = true)]
    public Int64? BatchID { get; set; }

    // Batch creation date
    [Column(Name = "Created")]
    public String Created { get; set; }

    // Other String columns the same as Created
    ...
}

[Table(Name = "Samples")]
public class Samples
{
    public virtual ICollection<Samples> samples { get; set; }
    public Samples()
    {
        samples = new HashSet<Samples>();
    }

    // Primary key - nullable to allow Autoincrement
    [Column(Name = "SampleID", IsPrimaryKey = true)]
    public Int64? SampleID { get; set; }

    // Foreign key to the Batches Table
    private EntityRef<Batches> _batch = new EntityRef<Batches>();
    [Association(Name = "FK_BatchID", IsForeignKey = true, 
                 Storage = "_batch", ThisKey = "FK_BatchID", 
                  OtherKey = "BatchID")]
    public Batches Batches
    {
        get { return _batch.Entity; }
        set { _batch.Entity = value; }
    }
    // Foreign key table entry
    [Column(Name = "FK_BatchID")]
    public Int64? FK_BatchID { get; set; }

    // Date the image was processed by the batch
    [Column(Name = "Created")]
    public String Created { get; set; }
    
    // Other String columns etc
    ...
 }

编辑:

在尝试修改列装饰(即 IsDbGenerated 和/或 DbType 等)失败后,我使用如下所示的 sqlite_sequence 实施了一项工作。这用于查找各种表 ID 的值,然后在创建新对象时使用这些值。然后这些都可以打包在一个事务中

 // Start by getting the latest autoincrement values
 var aiQuery = (from c in context.sqlite_sequence
                select c).ToList();

 Int64 batchId = 1 + aiQuery.Find(q => q.name == @"Batches").seq;
 Int64 sampleId = 1 + aiQuery.Find(q => q.name == @"Samples").seq;
 
 // Create objects etc
 ...

 // Then update the db once only
 context.Batches.InsertOnSubmit(newBatch);
 context.SubmitChanges();

如果没有更好的解决方案,我会接受这个作为答案

【问题讨论】:

  • Batch 没有可以添加新样本的 Samples 集合吗?
  • @Gert:是的,使用 sqlite_sequence 的hacky 使用允许在单个事务中添加具有多个样本的新批次。

标签: c# linq sqlite


【解决方案1】:

如果没有合适的解决方案,这是我的解决方法。

使用 sql_sequence 建立自动增量 Id 值,然后在创建的对象中显式使用这些值。

var aiQuery = (from sequence in sqlite_sequence
               select sequence).ToList();

BatchId = 1 + aiQuery.Find(q => q.name == @"Batches").seq;
SampleId = 1 + aiQuery.Find(q => q.name == @"Samples").seq;

为方便起见,我将其放在派生自 Linq.DataContext 的类中


然后可以按照以下伪代码在单个事务中添加多个插入。

Batch batch = new Batch { id = BatchId, ... }
foreach (int i=0; i<n; ++i)
{
   batch.AddSample(new Sample { id = SampleId+i, batchid = BatchId, ... });
}

// Update db
context.Batches.InsertOnSubmit(batch);
context.SubmitChanges();

【讨论】:

    猜你喜欢
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    相关资源
    最近更新 更多