使用外部对象更新文档

时间:2017-01-24 13:52:37

标签: ravendb

我有一个包含Song对象的数据库。歌曲类有> 30个房产。

我的音乐标记应用程序正在对文件系统上的歌曲进行更改。 然后使用文件名在数据库中进行查找。

现在我有一个Song对象,我在我的Tagging应用程序中通过读取物理文件创建了一个Song对象,我刚刚从数据库中检索到了我要更新的对象。 我以为我可以从数据库对象中获取ID,用我的本地歌曲对象替换数据库对象,设置保存的ID并存储它。 但是Raven声称我用不同的对象替换了对象。

我是否真的需要复制每一个属性,就像这样?

dbSong.Artist = songfromFilesystem.Artist;

dbSong.Album = songfromFileSystem.Album;

还是有其他可能性。

感谢,

赫尔穆特

编辑:

我有点太积极了。以下建议仅适用于测试程序。 在我的原始代码中执行此操作时,我得到以下异常:

Attempted to associate a different object with id 'TrackDatas/3452'

这是由以下代码生成的:

try
  {
    originalFileName = Util.EscapeDatabaseQuery(originalFileName);
    // Lookup the track in the database
    var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
    if (dbTracks.Count > 0)
    {
      track.Id = dbTracks[0].Id;
      _session.Store(track);
      _session.SaveChanges();
    }
  }
  catch (Exception ex)
  {
    log.Error("UpdateTrack: Error updating track in database {0}: {1}", ex.Message, ex.InnerException);
  }

我首先在数据库中查找一首歌并在dbTracks中获取一个TrackData对象。

track对象也是TrackData类型,我只是从刚刚检索到的对象中放入ID并尝试存储它,这就产生了上述错误。

我认为上面的消息告诉我对象属于不同的类型,而不是。

如果我使用AutoMapper,则会发生同样的错误。

任何想法?

3 个答案:

答案 0 :(得分:1)

您可以执行您尝试的操作:仅使用ID替换现有对象。如果它不起作用,你可能会做错其他的事情。 (在这种情况下,请告诉我们您的代码。)

在Raven中更新现有对象时,有几个选项:

选项1:只需使用与现有对象相同的ID保存对象:

var song = ... // load it from the file system or whatever
song.Id = "Songs/5"; // Set it to an existing song ID
DbSession.Store(song); // Overwrites the existing song

选项2:手动更新现有对象的属性。

var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.Artist = song.Artist;
existingSong.Album = song.Album;

选项3:动态更新现有对象:

var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.CopyFrom(song);

你有这样的代码:

// Inside Song.cs
public virtual void CopyFrom(Song other)
{
    var props = typeof(Song)
        .GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
        .Where(p => p.CanWrite);
    foreach (var prop in props)
    {
        var source = prop.GetValue(other);
        prop.SetValue(this, source);
    }
}

如果您经常发现自己必须这样做,请使用像AutoMapper这样的库。

Automapper可以使用一行代码自动将一个对象复制到另一个对象。

答案 1 :(得分:0)

现在您已经发布了一些代码,我看到了两件事:

首先,您是否有使用Advanced.DocumentQuery语法的原因?

// This is advanced query syntax. Is there a reason you're using it?
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();

以下是我如何使用标准LINQ语法编写代码:

var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
   .Where(t => t.Query == escapedFileName)
   .Select(t => t.Id);
if (existingTrackId != null)
{
   track.Id = existingTrackId;
   _session.Store(track);
   _session.SaveChanges();
}

最后,#2:什么是赛道?它是通过session.Load还是session.Query加载的?如果是这样,那将无法正常工作,并且会导致您的问题。如果从数据库加载了跟踪,则您需要创建一个新对象并保存:

 var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
   .Where(t => t.Query == escapedFileName)
   .Select(t => t.Id);
if (existingTrackId != null)
{
   var newTrack = new Track(...);
   newTrack.Id = existingTrackId;
   _session.Store(newTrack);
   _session.SaveChanges();
}

答案 2 :(得分:0)

这意味着您在会话中已经有一个具有相同ID的不同对象。对我来说,解决方法是使用一个新的会话。