context.SaveChanges() not updating data in SqlServer database - entity-framework-4.1

When I call context.SaveChanges() to update a specific product, the update is not registered in the database. I do not get any runtime error either. All I notice is that my product catalog is not updated. I still see the same values. When I run the debugger I notice that the connection state of the database is closed.
This is the class implementing the context.SaveChanges()
namespace SportsStore.Domain.Concrete
{
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products
{
get { return context.Products; }
}
public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
context.SaveChanges();
}
}
}
namespace SportsStore.Domain.Concrete
{
public class EFDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
}
}
namespace SportsStore.Domain.Entities
{
public class Product
{
[HiddenInput(DisplayValue=false)]
public int ProductID { get; set; }
public string Name { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
}

In the EFProductRepository class, prior to calling the context.SaveChanges() method in the SaveProduct method, you can use one of the following approaches to persist changes to the database.
public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
//One approach to persist changes to database
//var productInDB = context.Products.Single(x => x.ProductID ==product.ProductID);
//context.Entry(productInDB).CurrentValues.SetValues(product);
//context.SaveChanges();
//Alternate Approach
if (product.ProductID != 0)
{
context.Entry(product).State = System.Data.EntityState.Modified;
}
context.SaveChanges();
}

Related

how to extract particular field from JSON using NewtonSoft.Json in C#

I am using Newtonsoft.Json in my C# application and want to know how to extract accountId from following JSON content which stored in string.
Any help is really appreciated.
{ "AccountListResponse": { "Accounts": { "Account": [ {"accountId":"0001","accountIdKey":"key1","accountMode":"ON"}, {"accountId":"00021","accountIdKey":"key21","accountMode":"ON"}, {"accountId":"00031","accountIdKey":"key31","accountMode":"ON"} ] } } }
i tried reading api, but still couldn't find out how to use. becaise of array, it got more complicated.
first here is your model
public class Account
{
public string accountId { get; set; }
public string accountIdKey { get; set; }
public string accountMode { get; set; }
}
public class AccountListResponse
{
public Accounts Accounts { get; set; }
}
public class Accounts
{
public List<Account> Account { get; set; }
}
public class AccountListResponseMain
{
public AccountListResponse AccountListResponse { get; set; }
}
then now you loop through
var regModel = new AccountListResponseMain();
regModel.AccountListResponse =data.AccountListResponse;
for (int a = 0; a < data.Accounts.Length; a++)
{
var inv = new Account();
inv.accountId = a.accountId;
}
N/B not perfect but you get the idea

EF Core and Pomelo 5.0 - how to query the json column

I'm using last version of json implementation in Pomelo 5.0 and configure my maria server to use microsoft json serialisation.
var serverVersion = new MariaDbServerVersion(new Version(10, 3, 0));
services.AddDbContext<BusinessManagementDbContext>(options =>
{
options.UseMySql(databaseConfiguration.ConnectionString, serverVersion, m =>
{
m.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically);
m.EnableRetryOnFailure();
});
options.EnableSensitiveDataLogging(true);
});
I can save my POCO in my db but when I try to query my data, I get a null object.
Here's my data :
HeidySQL data
My query is pretty simple but I think I'm not using the right way for json query.
await Context.ValidatedSaleInvoices.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
It seems like there is no deserialization between my data and my property "Content".
How can I do this ?
Thank you,
Edit
My model is :
public class ValidateSaleInvoiceEntity
{
public int Id { get; set; }
public ValidateSaleInvoiceContent Content { get; set; }
}
public class ValidateSaleInvoiceContent
{
public string BusinessName { get; set; }
public DateTime Date { get; internal set; }
public string Number { get; internal set; }
public Address Address { get; internal set; }
public List<ValidateSaleInvoiceLineEntity> Lines { get; internal set; } = new List<ValidateSaleInvoiceLineEntity>();
}
public class ValidateSaleInvoiceLineEntity
{
public string Description { get; internal set; }
public decimal Quantity { get; internal set; }
public decimal UnitPriceVatExcluded { get; internal set; }
public decimal VatRate { get; internal set; }
}
And my json Result was like this (empty, like there waere no deserialisation: { "BusinessName":"", "Date":"", "Number":"" etc.}
My boss stop my poc about MariaDB Json implementation so I had to go back to this good old friend pure sql column :/ . That's why I haven"t a full json result. Sorry
For a property to serialize/deserialize JSON automatically to a POCO, you need to tell Pomelo, that the table column of the property is of the MySQL/MariaDB type json:
public class ValidateSaleInvoiceEntity
{
public int Id { get; set; }
[Column(TypeName = "json")] // <-- this is one way to do it
public ValidateSaleInvoiceContent Content { get; set; }
}
public class MyContext : DbContext
{
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ValidateSaleInvoiceEntity>()
.Property(e => e.Content)
.HasColumnType("json"); // <-- this is another way to do it
}
}
Here is a fully working console project:
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
// EF Core entities:
public class IceCream
{
public int IceCreamId { get; set; }
public string Name { get; set; }
// Either use this data annotation, or the corresponding Fluent API call (see
// OnModelCreating), to explicitly mark the column type as JSON.
[Column(TypeName = "json")]
public IceCreamDetails Details { get; set; }
}
// JSON class:
public class IceCreamDetails
{
public int Kilojoule { get; set; }
public int Rating { get; set; }
}
public class Context : DbContext
{
public DbSet<IceCream> IceCreams { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So68020732";
var serverVersion = ServerVersion.AutoDetect(connectionString);
optionsBuilder.UseMySql(connectionString, serverVersion, options => options
.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically))
.UseLoggerFactory(
LoggerFactory.Create(
configure => configure
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<IceCream>(
entity =>
{
// Either use this Fluent API call, or the corresponding data annotation
// (see the IceCreamDetails class), to explicitly mark the column type as JSON.
entity.Property(e => e.Details)
.HasColumnType("json");
entity.HasData(
new IceCream {IceCreamId = 1, Name = "Vanilla", Details = new IceCreamDetails { Kilojoule = 865, Rating = 9 }},
new IceCream {IceCreamId = 2, Name = "Chocolate", Details = new IceCreamDetails { Kilojoule = 903, Rating = 10 }});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var iceCreams = context.IceCreams
.OrderBy(i => i.IceCreamId)
.ToList();
Trace.Assert(iceCreams.Count == 2);
Trace.Assert(iceCreams[0].Details.Kilojoule == 865);
Trace.Assert(iceCreams[1].Details.Rating == 10);
}
}
}
You can find the most comprehensive JSON sample code on our repository (see the JSON mapping and query scenarios section).

Only want json returned when using WebApi 2 and EntityFramework

I am stumped on this for a couple of hours.
I am using WebApi 2 and Entity Framework 6.1.3. I am following this tutorial:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/
I would like to return only json. When I hit url http://localhost:11440/Api/Contacts. I am getting following error:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
I have the following models and controller defined:
Address.cs
namespace Blah_Application.Models
{
public class Address
{
public int AddressID { get; set; }
public int ContactID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public virtual Contact Contact { get; set; }
}
}
Contact.cs
using System.Collections.Generic;
namespace Blah_Application.Models
{
public class Contact
{
public Contact()
{
Phones = new HashSet<Phone>();
Addresses = new HashSet<Address>();
}
public int ContactID { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public bool Favorite { get; set; }
public string SmallImageUrl { get; set; }
public string LargeImageUrl { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string BirthDate { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
}
Phone.cs
namespace Ecitslos_Application.Models
{
public enum PhoneType { Home, Work, Mobile}
public class Phone
{
public int PhoneID {get; set;}
public int ContactID { get; set; }
public PhoneType PhoneType { get; set; }
public string Number { get; set; }
public virtual Contact Contact { get; set; }
}
}
ContactsController.cs
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Web.Http;
using System.Web.Http.Description;
using Blah_Application.Models;
namespace Ecitslos_Application.Controllers
{
public class ContactsController : ApiController
{
private Ecitslos_ApplicationContext db = new
Ecitslos_ApplicationContext();
// GET: api/Contacts
public IQueryable<Contact> GetContacts()
{
return db.Contacts;
}
// GET: api/Contacts/5
[ResponseType(typeof(Contact))]
public IHttpActionResult GetContact(int id)
{
Contact contact = db.Contacts.Find(id);
if (contact == null)
{
return NotFound();
}
return Ok(contact);
}
// PUT: api/Contacts/5
[ResponseType(typeof(void))]
public IHttpActionResult PutContact(int id, Contact contact)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != contact.ContactID)
{
return BadRequest();
}
db.Entry(contact).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ContactExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Contacts
[ResponseType(typeof(Contact))]
public IHttpActionResult PostContact(Contact contact)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Contacts.Add(contact);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = contact.ContactID }, contact);
}
// DELETE: api/Contacts/5
[ResponseType(typeof(Contact))]
public IHttpActionResult DeleteContact(int id)
{
Contact contact = db.Contacts.Find(id);
if (contact == null)
{
return NotFound();
}
db.Contacts.Remove(contact);
db.SaveChanges();
return Ok(contact);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool ContactExists(int id)
{
return db.Contacts.Count(e => e.ContactID == id) > 0;
}
}
}
You need to disable the XML formatter that is configured by default. Add the following line to the WebApiConfig class:
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
//route config etc. goes here
//disable xml serialization
config.Formatters.Remove(config.Formatters.XmlFormatter);
//prevent infinite recusion
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}
}
Way I am doing this in my project is the following. Hope you can get a pointer in the right direction.
// GET: api/Contacts/5
<Route("~/api/Contacts/{id}")>
<HttpGet>
public HttpResponseMessage GetContact(int id)
{
Contact contact = db.Contacts.Find(id);
if (contact == null)
{
Return Request.CreateResponse(HttpStatusCode.NotFound, "Contact Id not found", Configuration.Formatters.JsonFormatter);
}
Return Request.CreateResponse(HttpStatusCode.OK, contact, Configuration.Formatters.JsonFormatter);
}
Also, you have Contact in Phone and then you are instantiating Phone in Contact. This may create a cyclic dependency.

invalid object name 'dbo.Table' - EntityFramework 4.1

I keep getting this error when i run my MVC application. The app builds fine but throws this error on the runtime.
Here is the scenario.
[DisplayColumn("Name", "Name", false)]
public partial class ApplicationAction
{
public Guid ApplicationActionId { get; set; }
[Required, StringLength(150), Column("ActionName")]
public string Action { get; set; }
[Required, StringLength(150)]
public string Controller { get; set; }
[StringLength(150)]
public string Area { get; set; }
[StringLength(250)]
public string Description { get; set; }
//Navigation Properties
public virtual ICollection<ApplicationActionGroup> ApplicationActionGroups { get; set; }
public ApplicationAction()
{
ApplicationActionId = Guid.NewGuid();
}
}
public DbSet<ApplicationAction> ApplicationActions { get; set; }
public static ApplicationAction GetAction(string actionName, string controller, string area, IEnumerable<ApplicationAction> actions)
{
foreach (ApplicationAction a in actions)
{
if (a.Action.Equals(actionName, StringComparison.InvariantCultureIgnoreCase)
&& a.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase)
&& (
(string.IsNullOrEmpty(a.Area) && string.IsNullOrEmpty(area)) ||
(!string.IsNullOrEmpty(a.Area) && a.Area.Equals(area, StringComparison.InvariantCultureIgnoreCase))
)
)
{
return a;
}
}
return null;
}
I get an error on GetAction method. It comes up as Invalid object name 'dbo.ApplicationAction'. The sql database, there is a table called ApplicationActions. Not sure whats causing this error.
are you sure that [DisplayColumn("Name", "Name", false)]
is a valid attribute for a class?

Linq GetTable< > return empty rows

I have a very strange problem. I followed an MVC tutorial.
I have an interface:
namespace DomainModel.Abstract
{
public interface IProductsRepository
{
IQueryable<Product> Products { get; }
}
}
A repository inherits that interface:
namespace DomainModel.Concrete
{
public class SqlProductsRepository : IProductsRepository
{
private Table<Product> productsTable;
public SqlProductsRepository(string connectionString)
{
try
{
productsTable = (new DataContext(connectionString)).GetTable<Product>();
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
public IQueryable<Product> Products
{
get { return productsTable; }
}
}
}
My Product class looks like this:
namespace DomainModel.Entities
{
[Table(Name = "Products")]
public class Product
{
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
}
And my controller looks like this:
namespace WebUI.Controllers
{
public class ProductsController : Controller
{
private IProductsRepository productsRepository;
public ProductsController()
{
string connString = #"Data Source=INFO_KW-HZ7YX91;Initial Catalog=SportStore;Integrated Security=True";
productsRepository = new SqlProductsRepository(connString);
}
public ViewResult List()
{
return View(productsRepository.Products.ToList());
}
}
}
My Products table has 8 rows. When I run the web site, It displays 8 rows but they are all blanks and zero. When I debugged it, I can see productsTable has 8 rows with correct column names, but the string data are null and the integer data are zero.
What did I do wrong?
Thanks
It has been quite a while since last time I did custom attributes like this, but I guess you need to put [Column] for all properties you need to persist. Something like:
[Column]
public string Name { get; set; }
[Column]
public string Description { get; set; }
[Column]
public string Category { get; set; }
[Column]
public decimal Price { get; set; }
assuming that your sql table field names match the property names accordingly.
You didn't add [Column] attributes to any of your columns but your PK. LinqToSql is very attribute heavy, and hand-coding the classes will be fraught with risk and (most likely) frightening exceptions. You should use sqlmetal.exe or your own generator.