从ViewController保存时,无法从ObjectStateEntry获取命名空间

时间:2021-12-15 02:11:07

I'm attempting to create an Audit Log for my MVC, Entity Framework website project. I've been able to subscribe to SaveChanges() in my DBContext (and save to my database through another DBContext but same database).

我正在尝试为我的MVC,Entity Framework网站项目创建审核日志。我已经能够在我的DBContext中订阅SaveChanges()(并通过另一个DBContext但相同的数据库保存到我的数据库)。

My two questions in the end are:

我最后的两个问题是:

  • What does if (!entry.IsRelationship) do exactly? I have a ViewModel that calculates this as True when Saving and another as False. I would expect this to move into the rest of my method to save in the Audit Log.
  • if(!entry.IsRelationship)究竟做了什么?我有一个ViewModel,在保存时将其计算为True,另一个为False。我希望这会移到我的方法的其余部分以保存在审核日志中。

  • How can I get the full Namespace of my Object being modified? I was using this: entry.Entity.ToString() but doesn't seem to work when Saving/Editing from a View Model (details below)
  • 如何修改我的对象的完整命名空间?我正在使用这个:entry.Entity.ToString()但在从视图模型保存/编辑时似乎不起作用(详情如下)

Here is a basic setup that I have thus far (Album object/controller works, but AlbumView doesn't):

这是我到目前为止的基本设置(相册对象/控制器工作,但AlbumView没有):

Ablum class:

public class Album : BaseObject //BaseObject has a few properties, one is Oid (Guid)
{
    public string Name { get; set; }

    [Column(TypeName = "varchar(MAX)")]
    [DataType(DataType.MultilineText)]
    public string Description { get; set; }

    [Display(Name="Genres")]
    public virtual ICollection<AlbumsGenres> AlbumGenres { get; set; }

    [Display(Name="Artists")]
    public virtual ICollection<AlbumsArtists> AlbumArtists { get; set; }
}

AblumView class:

public class AlbumView
{
    [ScaffoldColumn(false)]
    public Guid Oid { get; set; }

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

    [Column(TypeName = "varchar(MAX)")]
    [DataType(DataType.MultilineText)]
    public string Description { get; set; }

    [Display(Name = "Genres")]
    public virtual List<AlbumsGenres> AlbumGenres { get; set; }

    [Display(Name = "Artists")]
    public virtual List<AlbumsArtists> AlbumArtists { get; set; }

}

AlbumsController (Audit works with something like this):

AlbumsController(Audit使用类似的东西):

public ActionResult Edit(Album album)
{
    if (ModelState.IsValid)
    {
        db.Entry(album).State = EntityState.Modified;
        db.SaveChanges(); //This is where SaveChanges() takes over (see below)
        return RedirectToAction("Index");
    }
    return View(album);
}

AlbumsViewController:

public ActionResult Edit(Guid id, AlbumView albumViewModel)
{
    //Omitting setup...

    //Album gets updated
    Album album = db.Albums.Find(id);
    album.Name = albumViewModel.Name;
    album.Description = albumViewModel.Description;

    //Other Objects are also updated, just an example:
    albumArtists = new AlbumsArtists();
    albumArtists.Oid = Guid.NewGuid();
    albumArtists.Album = db.Albums.Find(id);
    albumArtists.Artist = db.Artists.Find(item.Artist.Oid);

    //In the end it calls:
    db.SaveChanges();

    //Omitting other stuff...
}

On db.SaveChanges() within my DbContext:

在我的DbContext中的db.SaveChanges()上:

public class ApplicationDBContext : DbContext
{
    public ApplicationDBContext() : base("name=DefaultConnection") { }

    public System.Data.Entity.DbSet<ContentPub.Models.Music.Album> Albums { get; set; }
    //Other DBSet objects...

    public DbSet Set(string name)
    {
        return base.Set(Type.GetType(name));
    }

    public override int SaveChanges()
    {
        ApplicationLogDBContext logDb = new ApplicationLogDBContext();
        ChangeTracker.DetectChanges();

        ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;

        List<ObjectStateEntry> objectStateEntryList =
            ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added
                                                       | EntityState.Modified
                                                       | EntityState.Deleted)
            .ToList();

        foreach (ObjectStateEntry entry in objectStateEntryList)
        {
            Guid oid = Guid.Empty;

            try
            {
                if (!entry.IsRelationship) //I don't understand this (first of my two questions)
                {
                    switch (entry.State)
                    {
                        //Removed other cases

                        case EntityState.Modified:
                        {
                            oid = (Guid)entry.EntityKey.EntityKeyValues[0].Value;

                            //This is the area that I am having issues (second of the two questions)

                            //Below will work when I call db.SaveChanges() from the AlbumsController, 
                            //'entry.Entity.ToString()' will get 'x.Models.Music.Albums' and begin a query

                                var query = this.Set(entry.Entity.ToString()).AsNoTracking().Where("Oid == @0", oid);

                            //The issue with the above is when I have a ViewModel, returns something like
                            // = System.Data.Entity.DynamicProxies.Album_AF81C390156ACC8283ECEC668AFB22C4AD621EF70F8F64641D56852D19755BF3

                            //If the proper Namespace is returned, the next line works and Audit continues
                            var query = this.Set(entry.EntitySet.ElementType.ToString()).AsNoTracking().Where("Oid == @0", oid);

                            //Does a bunch of AuditLog stuff if the above issue doesn't fail
                            break;
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                throw new Exception("Log Error (" + entry.Entity.ToString() + ") - " + ex.ToString());
            }
        }
        return base.SaveChanges();
    }
}

entry.Entity.ToString() will return something like:

entry.Entity.ToString()将返回如下内容:

System.Data.Entity.DynamicProxies.Album_AF81C390156ACC8283ECEC668AFB22C4AD621EF70F8F64641D56852D19755BF3

In the AlbumView I am updating Album, and a bunch of other Objects. Not sure why it isn't returning x.Models.Music.Albums, is there a work-around, can someone explain or point me to other resources that I haven't found yet?

在AlbumView中,我正在更新相册和一堆其他对象。不确定为什么它没有返回x.Models.Music.Albums,有没有解决办法,有人可以解释或指向我还没有找到的其他资源吗?

1 个解决方案

#1


0  

While it isn't the most efficient solution, it still is a solution for now.

虽然它不是最有效的解决方案,但它现在仍然是一个解决方案。

I was able to do the following inside my db.SaveChanges() method:

我能够在db.SaveChanges()方法中执行以下操作:

//When AlbumView .BaseType was able to return x.Models.Music.Album
string strNamespace = entry.Entity.GetType().BaseType.ToString(); 

//Needed this if I was updating just an Object (ie: Album),
//would be nice to make something more concret
if (strNamespace == "x.Models.Core.BaseObject")
    strNamespace = entry.Entity.ToString();

//Continuing code
var query = this.Set(strNamespace).AsNoTracking().Where("Oid == @0", oid);

Found the answer here from another Question that I had not found before posting this question

在发布此问题之前,我在另一个问题中找到了答案

#1


0  

While it isn't the most efficient solution, it still is a solution for now.

虽然它不是最有效的解决方案,但它现在仍然是一个解决方案。

I was able to do the following inside my db.SaveChanges() method:

我能够在db.SaveChanges()方法中执行以下操作:

//When AlbumView .BaseType was able to return x.Models.Music.Album
string strNamespace = entry.Entity.GetType().BaseType.ToString(); 

//Needed this if I was updating just an Object (ie: Album),
//would be nice to make something more concret
if (strNamespace == "x.Models.Core.BaseObject")
    strNamespace = entry.Entity.ToString();

//Continuing code
var query = this.Set(strNamespace).AsNoTracking().Where("Oid == @0", oid);

Found the answer here from another Question that I had not found before posting this question

在发布此问题之前,我在另一个问题中找到了答案