Dbset is not getting the data from database - c#

class InvoiceAppDBContext: DbContext
{
public InvoiceAppDBContext() : base("InvoiceDBContext")
{
}
public DbSet<Users> User { get; set; }
public DbSet<Invoice> Invoices { get; set; }
}
class DataBaseUserRespository : IUser
{
private InvoiceAppDBContext _dbContext;
public DataBaseUserRespository()
{
_dbContext = new InvoiceAppDBContext();
}
public IEnumerable<Users> _userList
{
get
{
return _dbContext.User; // this is not working _userlist is showing null when i run it
}
}
public void SaveUser(Users user)
{
if(user.UserId == 0)
{
_dbContext.User.Add(user);
}
else
{
Users userEntity = _dbContext.User.Find(user.UserId);
userEntity.Change(user);
}
_dbContext.SaveChanges();
}
}
so DBSet or DBcontext is not getting the data from the table and putting it in IEnumerable<Users> list.
here i am debugging the userlist(accountList) and it is not showing data
hopefully this explains what problem i am getting :)

Related

Microsoft Entity Framework is not saving changes

Im currently trying to implement CRUD functionality with a dbfactory and generics with microsoft EF, but while listing entries is working, making changes to the db is currently not working.
public class AbstractDataModel
{
[Key]
public Guid gid { get; set; }
}
Model
class SalesOrder : AbstractDataModel
{
public int salesOrderID { get; set; }
public int productID { get; set; }
public int customerID { get; set; }
public Guid createdBy { get; set; }
public string dateCreated { get; set; }
public string orderDate { get; set; }
public string orderStatus { get; set; }
public string dateModified { get; set; }
}
A DBCore with some other functionality besides the ones listed here, which are not relevant for the factory
public class DBCore : DbContext
{
public static string connectionString = "myConnectionStringToDb";
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
Data Service which calls factory
class SalesOrderService : DBCore
{
public DbSet<SalesOrder> SalesOrders { get; set; }
public OkObjectResult GetAllSalesOrders()
{
DBFactory factory = new DBFactory();
return new OkObjectResult(JsonConvert.SerializeObject(factory.GetAll(SalesOrders)));
}
public OkObjectResult AddSalesOrder(SalesOrder order)
{
order.gid = Guid.NewGuid();
return DBFactory.AddOne(order);
}
public OkObjectResult UpdateSalesOrder(SalesOrder order)
{
return DBFactory.UpdateOne(order);
}
public OkObjectResult DeleteSalesOrder(SalesOrder order)
{
return DBFactory.DeleteOne(order);
}
}
simple CRUD-Factory,
class DBFactory : DBCore
{
public DbSet<UserModel> Users { get; set; }
public DbSet<SalesOrder> SalesOrders { get; set; }
public List<T> GetAll<T>(DbSet<T> dbset) where T : class
{
using (this)
{
return dbset.ToList();
}
}
public static OkObjectResult AddOne<T>(T data)
{
using (DBFactory factory = new DBFactory())
{
factory.Add(data);
factory.SaveChanges();
return new OkObjectResult("Entry was sucessfully added");
}
}
public static OkObjectResult UpdateOne<T>(T data)
{
using (DBFactory factory = new DBFactory())
{
factory.Update(data);
factory.SaveChanges();
return new OkObjectResult("Entry was sucessfully updated");
}
}
public static OkObjectResult DeleteOne<T>(T data)
{
using (DBFactory factory = new DBFactory())
{
factory.Attach(data);
factory.Remove(data);
factory.SaveChanges();
return new OkObjectResult("Entry was sucessfully removed");
}
}
}
Edit: Following the advices i changed the code so it should SaveChanges for the Factory, which also contains the context as a property. But it still doesnt seem to work for all database operations except listing all entries
Editv2: Thanks for the adivces it seems i have solved that problem, but a new one appeared :D
I can now do database operations like deleting entries, but now i cant list the entries anymore because the following error occurs, although the code there didnt really change:
"Executed 'GetAllOrders' (Failed, Id=5fb95793-572a-4545-ac15-76dffaa7a0cf, Duration=74ms)
[2020-10-23T14:33:43.711] System.Private.CoreLib: Exception while executing function: GetAllOrders. Newtonsoft.Json: Self referencing loop detected for property 'Context' with type 'FicoTestApp.Models.SalesOrder'. Path '[0].ChangeTracker'."
try adding
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
to your
startup.cs
it should to the job

How to insert graph in Entity Framework with circular dependency

This is how database structure looks like:
Vehicle has lot of CanNetworks and each CanNetwork has lot of ECUs. And that would save perfectly if that was only I have.
But, each vehicle also has one special ECU called gatewayECU so problem happens with saving because entity framework core does not know how to handle that scenario. It needs to insert vehicle before inserting ecus, but how to insert vehicle when ecu is not inserted.
This is what I tried: ignore (delete, invalidate) gatewayecu field (column is nullable in database), then I insert whole graph and then update vehicle with gatewayEcuId field I stored in some variable before doing anything.
Solution is not pretty. How to handle this scenario.
public class Vehicle : BaseEntity
{
public Vehicle()
{
CANNetworks = new List<CANNetwork>();
}
public List<CANNetwork>? CANNetworks { get; set; }
public ECU? GatewayECU { get; set; } = default!;
public int? GatewayECUId { get; set; }
}
public class CANNetwork : BaseEntity
{
public CANNetwork()
{
ECUs = new List<ECU>();
}
public string Name { get; set; } = default!;
public ICollection<ECU>? ECUs { get; set; }
public int VehicleId { get; set; }
public Vehicle? Vehicle { get; set; } = default!;
}
public class ECU : BaseEntity
{
public int CANNetworkId { get; set; }
public CANNetwork? CANNetwork { get; set; } = default!;
}
This is ugly solution which I don't want:
public async Task<int> Insert(Vehicle vehicleDefinition, ECU vehicleGatewayECU)
{
var result = -1;
using (var transaction = _databaseContext.Database.BeginTransaction())
{
result = await Insert(vehicleDefinition);
if (vehicleGatewayECU != null)
{
var ecu = await _databaseContext.ECUs.FirstOrDefaultAsync(x => x.Name == vehicleGatewayECU.Name && vehicleDefinition.Name == x.CANNetwork.Vehicle.Name);
if (ecu != null)
{
vehicleDefinition.GatewayECUId = ecu.Id;
result = await Update(vehicleDefinition);
transaction.Commit();
return result;
}
}
else
{
transaction.Commit();
}
}
return result;
}
EDIT:
I am now thinking about changing table structure in a way to get rid of gatewayECU field on Vehicle, and put some flag IsGatewayEcu in ECU table

How to syncronize records with Entity Framework Core for one to many relation during the update operation? Not add a new entity, just syncronize

I have the following entities: PushTemplate and PushTemplateMessage. One PushTemplate can have many PushTemplateMessages. I have repositories for this. All works for the create operation. But problem starts when I try to update PushTemplate and set new text for messages. Insetad of an update I see new one PushTemplateMessage. I'll show my code.
Entity PushTemplate:
public class PushTemplate
{
public int PushTemplateId { get; set; }
[Required]
public List<PushTemplateMessage> Messages { get; set; }
public DateTime CreatedAt { get; set; }
public PushTemplate()
{
CreatedAt = DateTime.UtcNow;
}
}
Entity PushTemplateMessage:
public class PushTemplateMessage
{
public int PushTemplateMessageId { get; set; }
public string PushTitle { get; set; }
public string PushMessage { get; set; }
public PushTemplate PushTemplate { get; set; }
}
Repository PushTemplateRepository:
public class PushTemplateRepository : IPushTemplateRepository
{
private readonly ApplicationDbContext _applicationContext;
public PushTemplateRepository(ApplicationDbContext applicationContext)
{
_applicationContext = applicationContext;
}
public IQueryable<PushTemplate> PushTemplates => _applicationContext.PushTemplates;
public void Save(PushTemplate pushTemplate)
{
if (pushTemplate.PushTemplateId == 0)
{
_applicationContext.PushTemplates.Add(pushTemplate);
}
else
{
PushTemplate dbEntity = _applicationContext.PushTemplates.Find(pushTemplate.PushTemplateId);
dbEntity.Messages = new List<PushTemplateMessage>();
_applicationContext.SaveChanges();
dbEntity.Messages = pushTemplate.Messages;
}
_applicationContext.SaveChanges();
}
}
Database context:
public class ApplicationDbContext : IdentityDbContext
{
private readonly string _connectionString;
public DbSet<PushTemplate> PushTemplates { get; set; }
public DbSet<PushTemplateMessage> TemplateMessages { get; set; }
public ApplicationDbContext(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("MakeAppDb");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql(_connectionString, b => b.MigrationsAssembly("MakeAppPushesNet_2"));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<PushTemplate>()
.HasMany(x => x.Messages)
.WithOne(y => y.PushTemplate)
.OnDelete(DeleteBehavior.Cascade);
}
}
And finally call to update operation from my controller:
PushTemplate pushTemplate = new PushTemplate
{
Messages = pushTemplateMessages // new list of messages
};
_pushTemplateRepository.Save(pushTemplate);
After this operation I have the old PushTemplateMessage and new version of PushTemplateMessage. But I need only new one! As you can see, in the repository I have tried to 'clean' old PushTemplateMessages to set then new list. But it continues to merge old data with new! Where is the mistake?
Ok, I have solved it. This post was helpful. This is from the answer.
So, if you want to synchronize (not add), even if you want set new values as NULL you have to use include("EntityName") on your db context. Now my save/update repository code is:
public void Save(PushTemplate pushTemplate)
{
if (pushTemplate.PushTemplateId == 0)
{
_applicationContext.PushTemplates.Add(pushTemplate);
}
else
{
PushTemplate dbEntity = _applicationContext.PushTemplates
.Include(x => x.Messages)
.FirstOrDefault(x => x.PushTemplateId == pushTemplate.PushTemplateId);
dbEntity.Messages = pushTemplate.Messages;
}
_applicationContext.SaveChanges();
}
As you can see I just use Include(). And now I can set null or synchronize it with a new list of values.

Receiving "InvalidOperationException:" in Asp.net MVC

I am trying to create a simple Asp.NET MVC database where a user can create an account, create categories for recipes, and then enter their recipe and file them into the category of their choosing. However, when I attempt to run the test to see if I can reach my list of categories(where I can also add a category), I get the following error message:
InvalidOperationException: Unable to resolve service for type 'LC101Project2017.Data.RecipeDbContext' while attempting to activate 'LC101Project2017.Controllers.CategoryController'.
I'm new to C# and am completely confused as to what I'm doing wrong. Here are my codes:
Controller: (CategoryController.cs)
public class CategoryController : Controller
{
private readonly RecipeDbContext context;
public CategoryController(RecipeDbContext dbContext)
{
context = dbContext;
}
public IActionResult Index()
{
List<RecipeCategory> categories = context.Categories.ToList();
return View(categories);
}
public IActionResult Add()
{
AddCategoryViewModel addCategoryViewModel = new AddCategoryViewModel();
return View(addCategoryViewModel);
}
[HttpPost]
public IActionResult Add(AddCategoryViewModel addCategoryViewModel)
{
if (ModelState.IsValid)
{
RecipeCategory newCategory = new RecipeCategory
{
Name = addCategoryViewModel.Name
};
context.Categories.Add(newCategory);
context.SaveChanges();
CategoryController: return Redirect("/Category");
};
return View(addCategoryViewModel);
}
}
Database (RecipeDbContext.cs)
public class RecipeDbContext : DbContext
{
public DbSet<Recipe> Recipes { get; set; }
public DbSet<RecipeCategory> Categories { get; set; }
}
MODEL (RecipeCategory.cs)
public class RecipeCategory
{
public int ID { get; set; }
public string Name { get; set; }
public IList<RecipeCategory> RecipeCategories { get; set; }
}
Check if you have configured to use your DbContext, RecipeDbContext, inside ConfigureServices method in Startup.cs
The method should look like this;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<RecipeDbContext >(options =>
options.UseSqlServer(Configuration.GetConnectionString("ConnectionStringName")));
}
Updated the answer in response to the comment by #Mel Mason
You need to declare a constructor that accepts DbContextOptions<RecipeDbContext>.
public class RecipeDbContext : DbContext
{
public DbSet<Recipe> Recipes { get; set; }
public DbSet<RecipeCategory> Categories { get; set; }
public RecipeDbContext(DbContextOptions<RecipeDbContext> options)
: base(options)
{ }
}
You can also check the official documentation:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-strings
Hope this helps.

Map Private Property

I have an Asp.Net project with Entity Framework 7 an i have a Email class with a list of attachments.
I don't want to leave that anyone add a item to my list, them i have
private List<Attachment> Resources { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
Now, I want to map to database the relationship with the property Resources instead Attachments.
Entity Framework 7 rise an Exception...
How i can do this.
Separate the this to two different model, one internal that maps to the database and another one that's available to users.
It's also the correct way of passing data between layers.
Hope it helps!
I agree with Itay.
Maybe this code example could help you.
Make entities that map to db tables.
public class EmailState
{
public int Id { get; private set; }
public List<AttachmentState> Resources { get; set; }
public static Email ToEmail(EmailState state)
{
return new Email(state);
}
}
public class AttachmentState
{
public static Attachment ToAttachment(AttachmentState state)
{
return new Attachment(state);
}
public Attachment ToAttachment()
{
return new Attachment(this);
}
}
Make classes that are available to users
public class Email
{
public Email()
{
this.State = new EmailState();
}
internal Email(EmailState state)
{
this.State = state;
}
internal EmailState State { get; set; }
public int Id { get; private set; }
public IEnumerable<Attachment> Attachments()
{
return this.State.Resources.Select(x => x.ToAttachment());
}
public void AddAttachment(Attachment attachment)
{
this.State.Resources.Add(attachment.State);
}
}
public class Attachment
{
public Attachment()
{
this.State = new AttachmentState();
}
internal Attachment(AttachmentState state)
{
this.State = state;
}
internal AttachmentState State { get; set; }
}
Define DbContext
public class EmailDbContext : DbContext
{
public DbSet<EmailState> Emails { get; set; }
public DbSet<AttachmentState> Attachments { get; set; }
}
Make repository
public interface IEmailRepository
{
void Add(Email email);
Email GetById(int emailId);
}
public class EmailRepository : IEmailRepository
{
private EmailDbContext _context;
public EmailRepository(EmailDbContext context)
{
_context = context;
}
public void Add(Email email)
{
_context.Emails.Add(email.State);
}
public Email GetById(int emailId)
{
EmailState emailState = _context.Emails.Single(x => x.Id == emailId);
return new Email(emailState);
}
}
Use it like this
using (var context = new EmailDbContext())
{
IEmailRepository repository = new EmailRepository(context);
var email = new Email();
repository.Add(email);
context.SaveChanges();
var emailFoundById = repository.GetById(email.Id);
}

Categories

Resources