使用EFCore的无效列警告我无法弄清楚

时间:2018-05-24 23:41:38

标签: c# asp.net-core-mvc entity-framework-core

我正在浏览以下多个网站教程(https://app.pluralsight.com/library/courses/asp-dot-net-core-restful-api-building/table-of-contents) 并尝试将这些知识应用到我创建基础应用程序的现有数据库中。

1)我在AssetRepository的AddAsset开头设置了一个断点。

2)我将以下POST请求发送到我的API:

POST http://localhost:6059/api/assets

{
    "bay": "X",
    "tile":  "1",
    "Serialnumber": "SERIAL",
    "devicename": "DEVICENAME",
    "assetspecs" : [
            {
                "assetattrid": "SIZE",
                "numvalue":12
            },
            {
                "assetattrid": "POWER",
                "numvalue":24
            }
        ]
}   

3)CreateAsset从AssetController运行,AddAsset从存储库通过控制器运行

4)调试器遇到_assetRepository.AddAsset(assetEntity)行;并从存储库中运行AddAsset

5)在执行AssetRepository.AddAsset的最后一行之前(_context.Asset.Add(asset);)调试器向我显示在进入行之前我有一组具有唯一ID的正确形式的记录 - 一切看起来都很好,并且应该将它添加到数据库中。

6)我点击了f11并且调试器跳转到我的上下文文件并运行OnConfiguring和OnModelCreating而没有任何问题然后返回到CreateAsset 控制器动作从中断。

7)我点击f11 AGAIN并检查if(!_assetRepository.Save())条件,该条件会抛出一个接受,告诉我有一个无效的列名Assetuid。在应用程序洞察调试输出中,列是大写的,所有其他列都以小写字母开头,看起来很奇怪。

我已经花了半天时间,如果有人可以提供帮助,我会感到茫然。还有一些可能涉及的文件我没有代表,如果你需要进一步查看,请告诉我,谢谢!!!!

aContext.cs

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Configuration;

namespace AssetAPI.Entities
{
    public partial class aContext : DbContext
    {
        public aContext(DbContextOptions<aContext> options) : base(options)
        {

        }

        public static IConfiguration Configuration;

        public virtual DbSet<Asset> Asset { get; set; }
        public virtual DbSet<Assetspec> Assetspec { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer(Configuration["connectionStrings:AssetDBConnectionString"])
                    .EnableSensitiveDataLogging();
            }
            else
            {
                optionsBuilder.EnableSensitiveDataLogging();
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Asset>(entity =>
            {
                entity.HasKey(e => e.Assetuid)
                    .ForSqlServerIsClustered(false);

                     entity.ToTable("asset");

                entity.HasIndex(e => e.Assetid)
                    .HasName("asset_indx7");

                entity.HasIndex(e => e.Assetuid)
                    .HasName("asset_ndx")
                    .IsUnique();

                entity.HasIndex(e => e.Barcode)
                    .HasName("asset_barcode");

                entity.HasIndex(e => e.Pluscphyloc)
                    .HasName("asset_ndx16");

                entity.HasIndex(e => e.Status)
                    .HasName("asset_ndx15");

                entity.HasIndex(e => new { e.Assetnum, e.Assetuid })
                    .HasName("asset_ndx17");

                entity.HasIndex(e => new { e.Assetnum, e.Siteid })
                    .HasName("asset_ndx11")
                    .IsUnique();

                entity.HasIndex(e => new { e.Assetnum, e.Status })
                    .HasName("asset_ndx8");

                entity.HasIndex(e => new { e.Orgid, e.Status })
                    .HasName("asset_ndx13");

                entity.HasIndex(e => new { e.Siteid, e.Ancestor })
                    .HasName("asset_ndx7");

                entity.HasIndex(e => new { e.Siteid, e.Assetnum })
                    .HasName("asset_ndx1")
                    .IsUnique()
                    .ForSqlServerIsClustered();

                entity.HasIndex(e => new { e.Siteid, e.Calnum })
                    .HasName("asset_ndx4");

                entity.HasIndex(e => new { e.Siteid, e.Location })
                    .HasName("asset_ndx6");

                entity.HasIndex(e => new { e.Siteid, e.Parent })
                    .HasName("asset_ndx2");

                entity.HasIndex(e => new { e.Siteid, e.Status })
                    .HasName("asset_ndx10");

                entity.HasIndex(e => new { e.Siteid, e.Vendor })
                    .HasName("asset_ndx3");

                entity.HasIndex(e => new { e.Assetid, e.Siteid, e.Moved })
                    .HasName("asset_ndx14")
                    .IsUnique();

                entity.HasIndex(e => new { e.Assetnum, e.Location, e.Siteid })
                    .HasName("asset_ndx12");

                entity.HasIndex(e => new { e.Itemnum, e.Siteid, e.Itemsetid })
                    .HasName("asset_ndx5");

                entity.HasIndex(e => new { e.Siteid, e.Location, e.Parent })
                    .HasName("asset_ndx9");

                entity.Property(e => e.Assetuid)
                    .HasColumnName("assetuid");
                    .ValueGeneratedNever();

              ..... Properties hidden, lots of them, came from scaffolding existing table

            });

            modelBuilder.Entity<Assetspec>(entity =>
            {
                entity.ToTable("assetspec");

                entity.HasIndex(e => e.Assetspecid)
                    .HasName("assetspec_ndx")
                    .IsUnique();

                entity.HasIndex(e => new { e.Assetattrid, e.Section })
                    .HasName("assetspec_ndx3");

                entity.HasIndex(e => new { e.Assetnum, e.Siteid })
                    .HasName("assetspec_ndx4");

                entity.HasIndex(e => new { e.Classstructureid, e.Assetattrid, e.Section })
                    .HasName("assetspec_ndx2");

                entity.HasIndex(e => new { e.Assetattrid, e.Assetnum, e.Section, e.Siteid, e.Linearassetspecid })
                    .HasName("assetspec_ndx1")
                    .IsUnique();

                entity.Property(e => e.Assetspecid)
                    .HasColumnName("assetspecid")
                    .ValueGeneratedNever();

                ...   ..... Properties hidden, lots of them, came from scaffolding existing table
            });
        }
    }
}

AssetRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using AssetAPI.Entities;

namespace AssetAPI.Services
{
    public class AssetRepository : IAssetRepository
    {
        private aContext _context;

        public AssetRepository(aContext context)
        {
            _context = context;
        }

        public void AddAsset(Entities.Asset asset)
        {
            Random rnd = new Random();
            asset.Assetid = rnd.Next(20000000, 30000000);
            asset.Assetuid = rnd.Next(20000000, 30000000);
            asset.Assetnum = rnd.Next(800000, 900000).ToString();
            asset.Barcode = asset.Assetnum;
            asset.Changedate = DateTime.Now;
            asset.Changeby = "123";
            asset.Langcode = "EN";
            asset.Siteid = "SITE";
            asset.Orgid = "ORG";



            // the repository fills the id (instead of using identity columns)
            if (asset.Assetspecs.Any())
            {
                foreach (var assetspec in asset.Assetspecs)
                {
                    Random rnd2 = new Random();

                    assetspec.Assetspecid = rnd2.Next(20000000, 30000000);
                    assetspec.Changedate = DateTime.Today;
                    assetspec.Assetnum = asset.Assetnum;
                    assetspec.Classstructureid = "1140";
                    assetspec.Orgid = "ORG";
                    assetspec.Siteid = "SITE";
                    assetspec.Continuous = 0;
                    assetspec.Displaysequence = 0;
                    assetspec.Inheritedfromitem = 0;
                    assetspec.Itemspecvalchanged = 0;
                    assetspec.Mandatory = 0;

                 }
            }



            _context.Asset.Add(asset);



        }

        public void AddAssetspecForAsset(string assetnum, Assetspec assetspec)
        {
            var asset = GetAsset(assetnum);
            if (asset != null)
            {
                assetspec.Assetnum = assetnum;
                assetspec.Changeby = "123";
                assetspec.Changedate = DateTime.Now;
                assetspec.Classstructureid = "1140";
                assetspec.Orgid = "ORG";
                assetspec.Siteid = "SITE";

                // if there isn't an id filled out (ie: we're not upserting),
                // we should generate one
                if (assetspec == null)
                {
                    Random rnd2 = new Random();

                    assetspec.Assetspecid = rnd2.Next(20000000, 30000000);
                    assetspec.Assetattrid = "RUSZ";
                    assetspec.Numvalue = 12;
                }
                asset.Assetspecs.Add(assetspec);
            }
        }

        public bool AssetExists(string assetnum)
        {
            return _context.Asset.Any(a => a.Assetnum == assetnum);
        }


        public Asset GetAsset(string assetnum)
        {
            return _context.Asset.FirstOrDefault(a => a.Assetnum == assetnum);
        }

        public IEnumerable<Entities.Asset> GetAssets()
        {
            // return _context.Asset.OrderBy(a => a.Barcode).ThenBy(a => a.Bay).ThenBy(a => a.Tile).Take(10).ToList();
            return _context.Asset.OrderByDescending(a => a.Bay).ThenBy(a => a.Tile).Take(10).ToList();
        }

        public IEnumerable<Entities.Asset> GetAssets(IEnumerable<string> Assetnums)
        {
            return _context.Asset.Where(a => Assetnums.Contains(a.Assetnum))
                .OrderBy(a => a.Barcode)
                .OrderBy(a => a.Bay)
                .OrderBy(a => a.Tile)
                .ToList();
        }

        public IEnumerable<Assetspec> GetAssetspecsForAsset(string assetnum)
        {
            return _context.Assetspec
                        .Where(b => b.Assetnum == assetnum && b.Assetattrid == "RUSZ").OrderBy(b => b.Assetnum).ToList();
        }


        public bool Save()
        {
            return (_context.SaveChanges() >= 0);
        }

        public Assetspec GetAssetspecsForAsset(string assetnum, long assetspecId)
        {
            return _context.Assetspec
                          .Where(b => b.Assetnum == assetnum && b.Assetspecid == assetspecId).FirstOrDefault();
        }
    }
}

Asset.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace AssetAPI.Entities
{
    public partial class Asset
    {


        [Key]
        public long Assetuid { get; set; }
        public string Bay { get; set; }
        public string Tile { get; set; }
        public string TileLocation { get; set; }
        public string Serialnumber { get; set; }
        public string Devicename { get; set; }

           ....scaffolded properties hidden

        public  virtual ICollection<Assetspec> Assetspecs { get; set; } = new List<Assetspec>();
    }
}

AssetsController.cs

using AssetAPI.Models;
using AssetAPI.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using AssetAPI.Entities;

namespace AssetAPI.Controllers
{
    [Route("api/assets")]
    public class AssetsController : Controller
        {
            private IAssetRepository _assetRepository;

        public AssetsController(IAssetRepository assetRepository)
        {
            _assetRepository = assetRepository;
        }
        public IActionResult GetAssets()
        {
            var assetsFromRepo = _assetRepository.GetAssets();

            var assets = Mapper.Map<IEnumerable<AssetDTO>>(assetsFromRepo);

            return Ok(assets);
        }

        [HttpGet("{assetnum}", Name = "GetAsset")]
        public IActionResult GetAsset(string assetnum)
        {
            var assetFromRepo = _assetRepository.GetAsset(assetnum); //Run GetAsset method for the passed in Assetid from AssetRepository

            if (assetFromRepo == null)
            {
                return NotFound();
            }

            var asset = Mapper.Map<AssetDTO>(assetFromRepo); //Map the entity to the DTO
            return Ok(asset); //Return the result in JSON format
        }


        //[FromBody] attribute signifies that parameter should be serialized from the request body into AssetForCreationDTO
        [HttpPost]
        public IActionResult CreateAsset([FromBody] AssetForCreationDTO asset)
        {
            //If the input provider in the request body was correctly serialized to an AssetForCreationDTO
            if (asset == null)
            {
                return BadRequest();
            }

            var assetEntity = Mapper.Map<Asset>(asset); //Map the entity to the DTO

            _assetRepository.AddAsset(assetEntity); //Add the entity to the DBContext

            if (!_assetRepository.Save()) //If the new resource cannot be saved
            {
                throw new Exception("Creating asset failed upon save");
                return StatusCode(500, "A problem occured.");
            }

            //Map the results again to learn the ID of the newly created resource
            var assetToReturn = Mapper.Map<AssetDTO>(assetEntity);

            //In case of a successful post, return 201 created response with location header
            //First param = name of route
            //Second = anon type containing new resource id
            //Third = Response body of newly created resource
            return CreatedAtRoute("GetAsset", new { assetnum =  assetToReturn.assetnum }, assetToReturn);
        }


    }
}

AssetDTO.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AssetAPI.Models
{
    public class AssetDTO
    {

        public string assetnum { get; set; }
        public string Barcode { get; set; }
        public string Bay { get; set; }
        public string Tile { get; set; }
        public string TileLocation { get; set; }
        public string Serialnumber { get; set; }
        public string Devicename { get; set; }
    }
}

AssetForCreationDTO:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AssetAPI.Models
{
    public class AssetForCreationDTO
    {
        public string Bay { get; set; }
        public string Tile { get; set; }
        public string TileLocation { get; set; }
        public string Serialnumber { get; set; }
        public string Devicename { get; set; }
        public ICollection<AssetspecForCreationDTO> Assetspecs { get; set; } = new List<AssetspecForCreationDTO>();
    }
}

1 个答案:

答案 0 :(得分:1)

解决了我的问题。

由于此代码背后的应用程序使用表格并且我将ASSETUID错误地设置为关键字段,因此我没有像EFcore那样强制执行关系。

由于assetspec实体没有ASSETUID列,根据我所做的一些研究,这会导致导航属性出现问题。

我将PK改为ASSETNUM;既然两个实体都有ASSETNUM作为财产,我现在都很好!