无法使用Entity Framework Core 2.0更新或创建数据

时间:2018-01-10 01:09:33

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

编辑:已经过了PUT中的问题(是一个空值进入非空字段),但仍然遇到POST问题

我正在尝试使用EF Core 2在我的项目中设置一个简单的通用存储库。获取和更新工作正常,但我遇到了Create的问题。具体而言,控制器中HttpPost接收的值为空。奇怪的是,HttpPut在控制器中运行良好,公司收到了所有数据。

这是我的通用回购类:

public class GenericRepository<TEntity> : IGenericRepository<TEntity>
    where TEntity : class, IEntity
{
    protected DriverDbContext _dbContext;
    protected DbSet<TEntity> _dbSet;

    public GenericRepository(DriverDbContext dbContext)
    {
        _dbContext = dbContext;
        _dbSet = dbContext.Set<TEntity>();
    }

    public async Task<IEnumerable<TEntity>> GetAll()
    {
        return await _dbSet.AsNoTracking().ToListAsync();
    }

    public async Task<TEntity> GetById(long id)
    {
        return await _dbSet
            .AsNoTracking()
            .FirstOrDefaultAsync(e => e.Id == id);
    }

    public async Task Create(TEntity entity)
    {
        _dbSet.Add(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task Update(TEntity entity)
    {
        // entity has good data but SavaChangesAsync does nothing
        _dbSet.Update(entity);
        await _dbContext.SaveChangesAsync();
    }

    public async Task Delete(long id)
    {
        var entity = await _dbSet.FindAsync(id);
        _dbSet.Remove(entity);
        await _dbContext.SaveChangesAsync();
    }

}

这是我的控制器:

[Produces("application/json")]
[Route("api/Company")]
public class CompanyController : Controller
{

    private ICompanyRepository _repository;

    public CompanyController(ICompanyRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public async Task<IActionResult> GetCompanies()
    {
        return Json(await _repository.GetAll());
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetCompany(int id)
    {
        var company = await _repository.GetById(id);

        if (company == null)
        {
            return NotFound();
        }
        return Json(company);
    }

    [HttpPost()]
    public async Task<IActionResult> CreateCompany([FromBody]CompanyViewModel company)
    {
        if (company == null)
        {
            return BadRequest();
        }

        var newCompany = Mapper.Map<Company>(company);

        await _repository.Create(newCompany);

        return Created($"/api/company/{company.Name}", Mapper.Map<CompanyViewModel>(newCompany));

    }

    [HttpPut()]
    public async Task<IActionResult> UpdateCompany([FromBody]CompanyViewModel company)
    {
        if (company==null)
        {
            return BadRequest();
        }

        if (_repository.GetById(company.Id) == null)
        {
            return NotFound();
        }

        var updatedCompany = Mapper.Map<Company>(company);
        await _repository.Update(updatedCompany);
        return new NoContentResult();
    }
}

以下是公司实体:

public class Company : IEntity
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public string Comments { get; set; }
    public string Type { get; set; }
    public bool Blacklisted { get; set; }
    public string BlacklistedComments { get; set; }
    public string BrokerAgreementStatus { get; set; }
    public float CompanyInvoiceDiscount { get; set; }
    public float PassThroughFee { get; set; }
    public int StandardHoursBilled { get; set; }
    public float StandardGM { get; set; }
    public float StandardMarkupFromBase { get; set; }
    public float StandardMarkupFromLoaded { get; set; }
    public float StandardEquipmentCost { get; set; }
    public long LastEditByUserID { get; set; }
    public DateTime? LastEditDate { get; set; }
}

以下是公司视图模型:

public class CompanyViewModel
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
    public string Comments { get; set; }
    public string Type { get; set; }
    public bool Blacklisted { get; set; }
    public string BlacklistedComments { get; set; }
    public string BrokerAgreementStatus { get; set; }
    public float CompanyInvoiceDiscount { get; set; }
    public float PassThroughFee { get; set; }
    public int StandardHoursBilled { get; set; }
    public float StandardGM { get; set; }
    public float StandardMarkupFromBase { get; set; }
    public float StandardMarkupFromLoaded { get; set; }
    public float StandardEquipmentCost { get; set; }
    public long LastEditByUserId { get; set; }
    public DateTime LastEditDate { get; set; }
}

这是我有棱有角的公司服务:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Observable } from 'rxjs/Rx';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';

import { Company } from './company';
import { MessageService } from '../message/message.service';

const httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable()
export class CompanyService {

    private baseUrl = 'api/company';

    constructor(
        private http: HttpClient,
        private messageService: MessageService) {
    }

    private log(message: string) {
        this.messageService.add('CompanyService: ' + message);
    }

    getCompanies(): Observable<Company[]> {
        return this.http.get<Company[]>(this.baseUrl)
            .pipe(
                tap(companies => this.log(`fetched companies`)),
                catchError(this.handleError('getCompanies', []))
                );
    }

    //Handle Http operation that failed.
    //Let the app continue.
    //@param operation - name of the operation that failed
    //@param result - optional value to return as the observable result

    getCompany(id: number): Observable<Company> {
        if (id === 0) {
            return Observable.of(this.initializeCompany());
        }
        return this.http.get<Company>(`${this.baseUrl}/${id}`).pipe(
            tap(_ => this.log(`fetched Company id=${id}`)),
            catchError(this.handleError<Company>(`getCompany id=${id}`))
        );
        }

    initializeCompany(): Company {
        return {
            id: 0,
            name: null,
            address: null,
            city: null,
            state: null,
        };
    }

    saveCompany(company: Company): Observable<Company> {
        if (company.id === null) {
            return this.addCompany(company);
        }
        return this.updateCompany(company);
    }

    updateCompany(company: Company): Observable<Company> {
        return this.http.put<Company>(this.baseUrl, company, httpOptions).pipe(
            tap((company: Company) => this.log(`updated company id=${company.id}`)),
            catchError(this.handleError<any>('updateCompany'))
        );
    }

    addCompany(company: Company): Observable<Company> {
        return this.http.post<Company>(this.baseUrl, company, httpOptions).pipe(
            tap((company: Company) => this.log(`added company id=${company.id}`)),
            catchError(this.handleError<any>('addCompany'))
        );
    }

    private handleError<T>(operation = 'operation', result?: T) {
        return (error: any): Observable<T> => {

            // TODO: send the error to remote logging infrastructure
            console.error(error); // log to console instead

            // TODO: better job of transforming error for user consumption
            //this.log(`${operation} failed: ${error.message}`);

            // Let the app keep running by returning an empty result.
            return of(result as T);
        };
    }


}

这是startup.cs

public class Startup
{

    private IConfiguration _config;

    public Startup(IConfiguration config)
    {
        _config = config;
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DriverDbContext>(options => options.UseSqlServer(_config.GetConnectionString("DriverDBConnection")));

        services.AddMvc();

        services.AddScoped<ICompanyRepository, CompanyRespository>();


    } 

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true
            });
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        Mapper.Initialize(config =>
        {
            config.CreateMap<CompanyViewModel, Company>().ReverseMap();
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
    }
}

CompanyRespository是GenericRepository的空子类

以下是Post的请求有效负载:

{"id":null,
"name":"Some Company",
"address":null,
"city":null,
"state":"",
"zipcode":null,
"phone":null,
"email":null,
"comments":null,
"type":null,
"blacklisted":false,
"blacklistedComments":null,
"brokerAgreementStatus":"N/A",
"companyInvoiceDiscount":0,
"passThroughFee":0,
"standardHoursBilled":0,
"standardGM":0,
"standardMarkupFromBase":0,
"standardMarkupFromLoaded":0,
"standardEquipmentCost":0,
"lastEditByUserID":0,
"lastEditDate":"2018-01-10T23:03:05.303Z"}

这是请求标题

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Connection:keep-alive
Content-Length:447
Content-Type:application/json
Host:localhost:56241
Origin:http://localhost:56241
Referer:http://localhost:56241/companies/0/edit
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36

1 个答案:

答案 0 :(得分:0)

public async Task Create(TEntity entity)
{
    _dbSet.Add(entity);
    await _dbContext.SaveChangesAsync();
}

public async Task Update(TEntity entity)
{
    // entity has good data but SavaChangesAsync does nothing
    _dbSet.Update(entity);
    _dbContext.Entry(entity).State = EntityState.Modified;
    await _dbContext.SaveChangesAsync();
}

public async Task Delete(long id)
{
    var entity = await _dbSet.FindAsync(id);
    if (_dbContext.Entry(entity).State = EntityState.Detached)
        _dbSet.Attach(entity);
    _dbSet.Remove(entity);
    await _dbContext.SaveChangesAsync();
}