문제

나는 ASP.NET MVC의 새로운 기능을하고, 학습을 위해 간단한 블로그 응용 프로그램 (ASP.NET MVC5, EF6)을 연구합니다.

EF 코드 첫 번째 마이그레이션이있는 솔루션 아키텍처의 저장소 패턴을 사용하고 있습니다. DI를위한 NINJECT. 클라이언트 측면에서 jQuery 그리드를 사용하여 게시물, 범주 및 태그를 관리합니다.

- blog.model : post.cs, category.cs, tags.cs

public class Post
{
    [Required(ErrorMessage = "Id is required")]
    public int Id { get; set; }

    [Required(ErrorMessage = "Title is required")]
    [StringLength(500, ErrorMessage = "Title cannot be more than 500 characters long")]
    public string Title { get; set; }

    [Required(ErrorMessage = "Short description is required")]
    public string ShortDescription { get; set; }

    [Required(ErrorMessage = "Description is required")]
    public string Description { get; set; }

    public bool Published { get; set; }

    [Required(ErrorMessage = "PostedOn date is required")]
    public DateTime PostedOn { get; set; }

    public DateTime? ModifiedOn { get; set; }

    [ForeignKey("Category")]
    public virtual int CategoryId { get; set; }

    public virtual Category Category { get; set; }

    public virtual IList<Tag> Tags { get; set; }
}

public class Category
{
    [Key]
    public int CategoryId { get; set; }

    [Required(ErrorMessage = "Category Name is required")]
    [StringLength(500,ErrorMessage = "Category name length cannot exceed 500")]
    public string Name { get; set; }

    [Required(ErrorMessage = "Category Name is required")]
    [StringLength(500, ErrorMessage = "Category name length cannot exceed 500")]     
    public string Description { get; set; }

    [JsonIgnore] 
    public virtual IList<Post> Posts { get; set; }
}

public class Tag
{
    public int Id { get; set; }

    [Required(ErrorMessage = "Name is required")]
    [StringLength(500, ErrorMessage = "Name length should not exceed 500 characters")]
    public string Name { get; set; }

    public string Description { get; set; }

    [JsonIgnore]
    public IList<Post> Posts { get; set; }

}
.

- blog.repository : blogRepository, iBlogRepository, blogContext

public interface IBlogRepository
{
    int SavePost(Post post);

    //Other methods...
}

public class BlogRepository : BlogContext, IBlogRepository
{
    public BlogContext _db;

    public BlogRepository(BlogContext db)
    {
        _db = db;
    }

    public int SavePost(Post post)
    {
        _db.Posts.Add(post);
        _db.SaveChanges();
        return post.Id;
    }

    //Other implementations...
}

public class BlogContext : DbContext, IDisposedTracker
{
    public BlogContext() : base("BlogDbConnection") { }

    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }
    public DbSet<Category> Categories { get; set; }

    public bool IsDisposed { get; set; }

    protected override void Dispose(bool disposing)
    {
        IsDisposed = true;
        base.Dispose(disposing);
    }
.

- blog.web : admincontroller.cs, ninjectwebcommon.cs

AdminController는 JSON 형식으로 데이터를 보내거나 소비합니다.

public class AdminController : Controller
{    
    private readonly IBlogRepository _blogRepository;

    public AdminController(IBlogRepository blogRepository)
    {
        _blogRepository = blogRepository;
    }

    //POST: /Admin/CreatePost
    [HttpPost, ValidateInput(false)]
    public ContentResult CreatePost([ModelBinder(typeof(PostModelBinder))] Post model)
    {
        string json;

        ModelState.Clear();

        if (TryValidateModel(model))
        {
            var id = _blogRepository.SavePost(model);
            json = JsonConvert.SerializeObject(
                new
                {
                    id = id,
                    success = true,
                    message = "Post saved successfully."
                });
        }
        else
        {
            json = JsonConvert.SerializeObject(
                new
                {
                    id = 0,
                    success = false,
                    message = "Post not saved."
                });
        }
        return Content(json, "application/json");
    }
}

public static class NinjectWebCommon 
{
  private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<BlogContext>().ToSelf(); //This isn't helping either
        kernel.Bind<IBlogRepository>().To<BlogRepository>();
    }   
}
.

INDS에서받은 카테고리 목록 및 그리드에서받은 태그 목록이 응용 프로그램 모델의 실제 객체에 맵핑되지 않기 때문에 유효성 검사 예외를 사용하면 사용자 정의 모델 바인딩을 사용하고 있습니다. 따라서 사용자 정의 모델 바인딩에서는 그리드에서 수신 한 실제 객체가있는 POST 객체를 채우고 있습니다. 이 게시물 개체는 DBContext 및 저장소를 사용하여 데이터베이스에 저장하는 컨트롤러로 전송됩니다.

public class PostModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,  ModelBindingContext bindingContext)
    {
        var post = (Post)base.BindModel(controllerContext, bindingContext);

        **var blogRepository = new BlogRepository(new BlogContext());**//I think here I need to inject the dependency for BlogContext, but don't know how to do that.

        if (post.Category != null)
        {
            post.Category = blogRepository._db.Categories.AsNoTracking().Single(c => c.CategoryId == post.Category.CategoryId);
        }

        var tags = bindingContext.ValueProvider.GetValue("Tags").AttemptedValue.Split(',');

        if (tags.Length > 0)
        {
            post.Tags = new List<Tag>();

            foreach (var tag in tags)
            {
                var id = int.Parse(tag.Trim());
                post.Tags.Add(blogRepository._db.Tags.AsNoTracking().Single(t => t.Id == id));
            }
        }

        if (bindingContext.ValueProvider.GetValue("oper").AttemptedValue.Equals("edit"))
            post.ModifiedOn = DateTime.UtcNow;
        else
            post.PostedOn = DateTime.UtcNow;

        return post;
    }
}
.

문제 : 게시물이 저장되면 데이터 컨텍스트는 해당 테이블의 카테고리 및 태그에 대한 새 행을 삽입합니다. 새로 생성 된 게시물은 외래 키 열에서 새 범주 (ID : 22)를 나타냅니다.

포스트 :

여기에 이미지 설명

카테고리 :

여기에 이미지 설명

태그 :

여기에 이미지 설명을 입력하십시오

이유는 엔티티가 저장 될 때 다른 objectContext에 연결되어 있고 현재 컨텍스트에 연결해야하지만 방법을 모르겠습니다. 비슷한 질문은 전에 물어 봤지만 그 답변은 받아 들여지지 않았습니다. 어떤 도움이 크게 감사 할 것입니다.

도움이 되었습니까?

해결책

카테고리와 태그 값을 objectContext에 첨부하여 위의 문제를 수동으로 해결할 수있었습니다. 이는 변경 해야하는 변경 사항을 나타냅니다.이렇게하면 카테고리 및 태그의 상위 테이블에 새 항목이 생성되지 않습니다.

  public int SavePost(Post post)
    {
        //attach tags to db context for Tags to tell EF 
        //that these tags already exist in database
        foreach (var t in post.Tags)
        {
            _db.Tags.Attach(t);
        }

        //tell EF that Category already exists in Category table
        _db.Entry(post.Category).State = EntityState.Modified;

        _db.Posts.Add(post);

        _db.SaveChanges();

        return post.Id;
    }

 public void EditPost(Post post)
    {
        if (post == null) return;

        //get current post from database
        var dbPost = _db.Posts.Include(p => p.Tags).SingleOrDefault(p => p.Id == post.Id);

        //get new list of tags
        var newTags = post.Tags.Select(tag => new Tag() { Id = tag.Id, Name = tag.Name, Description = tag.Description }).ToList();

        if (dbPost != null)
        {
            //get category from its parent table and assign to db post
            dbPost.Category = _db.Categories.Find(post.Category.CategoryId); ;

            //set scalar properties
            _db.Entry(dbPost).CurrentValues.SetValues(post);

            //remove tags from post in database
            foreach (var t in dbPost.Tags.ToList())
            {
                if (!newTags.Contains(t))
                {
                    dbPost.Tags.Remove(t);
                }
            }

            //add tags to post in database
            foreach (var t in newTags)
            {
                if (dbPost.Tags.All(p => p.Id != t.Id))
                {
                    var tagInDb = _db.Tags.Find(t.Id);
                    if (tagInDb != null)
                    {
                        dbPost.Tags.Add(tagInDb);
                    }
                }
            }
        }

        //save changes
        _db.SaveChanges();
    }
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top