Update Document with external object

北慕城南 提交于 2020-02-05 04:07:05

问题


i have a database containing Song objects. The song class has > 30 properties.

My Music Tagging application is doing changes on a song on the file system. It then does a lookup in the database using the filename.

Now i have a Song object, which i created in my Tagging application by reading the physical file and i have a Song object, which i have just retrieved from the database and which i want to update. I thought i just could grab the ID from the database object, replace the database object with my local song object, set the saved id and store it. But Raven claims that i am replacing the object with a different object.

Do i really need to copy every single property over, like this?

dbSong.Artist = songfromFilesystem.Artist;

dbSong.Album = songfromFileSystem.Album;

Or are there other possibilities.

thanks,

Helmut

Edit:

I was a bit too positive. The suggestion below works only in a test program. When doing it in my original code i get following exception:

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

This is produced by following code:

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);
  }

I am first looking up a song in the database and get a TrackData object in dbTracks.

The track object is also of type TrackData and i just put the ID from the object just retrieved and try to store it, which gives the above error.

I would think that the above message tells me that the objects are of different types, which they aren't.

The same error happens, if i use AutoMapper.

any idea?


回答1:


You can do what you're trying: replace an existing object using just the ID. If it's not working, you might be doing something else wrong. (In which case, please show us your code.)

When it comes to updating existing objects in Raven, there are a few options:

Option 1: Just save the object using the same ID as an existing object:

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

Option 2: Manually update the properties of the existing object.

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

Option 3: Dynamically update the existing object:

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

Where you've got some code like this:

// 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);
    }
}

If you find yourself having to do this often, use a library like AutoMapper.

Automapper can automatically copy one object to another with a single line of code.




回答2:


Now that you've posted some code, I see 2 things:

First, is there a reason you're using the Advanced.DocumentQuery syntax?

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

Here's how I'd write your code using standard LINQ syntax:

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();
}

Finally, #2: what is track? Was it loaded via session.Load or session.Query? If so, that's not going to work, and it's causing your problem. If track is loaded from the database, you'll need to create a new object and save that:

 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();
}



回答3:


This means you already have a different object in the session with the same id. The fix for me was to use a new session.



来源:https://stackoverflow.com/questions/41829986/update-document-with-external-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!