Data not seeding into database - c#

I am following a tutorial on the documentation to try create my own database. The data was seeding properly with 3 tables and now I have added 6 I can't get the data to seed. I have tried creating a migration and updating the database. I did change some of the ON DELETE CASCADE to ON DELETE NO ACTION as I was getting an error with cascading and I am not sure if that is the reason that it isn't seeding.
For reference it was the tables 'Car' , 'PaymentPlan' & 'SalesMan' that was working previously
Initialise code:
using GarageSales.Data;
using GarageSales.Models;
using System;
using System.Linq;
namespace GarageSales.Data
{
public static class DbInitializer
{
public static void Initialize(GarageSalesContext context)
{
//context.Database.EnsureCreated();
// Look for any Cars.
if (context.Cars.Any())
{
return; // DB has been seeded
}
var Customers = new Customer[]
{
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT35 0JW", RentalID=1, CarID=1, SalesManID=1},
new Customer{FirstName="Amelie", LastName="Bush", Gender="Female", Address="54 Beach Gardens", PostCode="BT34 0JE", RentalID=2, CarID=2, SalesManID=2},
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT67 0JW", RentalID=3, CarID=3, SalesManID=3}
};
foreach (Customer customer in Customers)
{
context.Customer.Add(customer);
}
context.SaveChanges();
var Cars = new Car[]
{
new Car{Model="I8",Manufacturer="BMW",EngineSize="1.5 L 3-cylinder"},
new Car{Model="A5",Manufacturer="Audi",EngineSize="5.2 L V10"},
new Car{Model="R8",Manufacturer="Audi",EngineSize="1.5 L 3-cylinder"}
};
foreach (Car car in Cars)
{
context.Cars.Add(car);
}
context.SaveChanges();
var SalesMen = new SalesMan[]
{
new SalesMan{FirstName="Darren",SurName="Dooning"},
new SalesMan{FirstName="Jim",SurName="Campbell"},
new SalesMan{FirstName="Jade",SurName="Mull"},
};
foreach (SalesMan SalesMan in SalesMen)
{
context.SalesMen.Add(SalesMan);
}
context.SaveChanges();
var Rentals = new Rental[]
{
new Rental{Price=150, Duration=36, Quote=3500, CustomerID=1, CarID=1, SalesManID=1},
new Rental{Price=200, Duration=24, Quote=2000, CustomerID=2, CarID=2, SalesManID=2},
new Rental{Price=400, Duration=12, Quote=4500, CustomerID=3, CarID=3, SalesManID=3}
};
foreach (Rental Rental in Rentals)
{
context.Rental.Add(Rental);
}
context.SaveChanges();
var PaymentPlans = new PaymentPlan[]
{
new PaymentPlan{CarID=1,SalesManID=1},
new PaymentPlan{CarID=2,SalesManID=2},
new PaymentPlan{CarID=3,SalesManID=3}
};
foreach (PaymentPlan PaymentPlan in PaymentPlans)
{
context.PaymentPlans.Add(PaymentPlan);
}
context.SaveChanges();
var Duration = new Duration[]
{
new Duration{DurationLength=36, RentalID=1, SalesManID=1},
new Duration{DurationLength=24, RentalID=2, SalesManID=2},
new Duration{DurationLength=12, RentalID=3, SalesManID=3}
};
foreach (Duration duration in Duration)
{
context.Duration.Add(duration);
}
context.SaveChanges();
}
}
}
Context class (The dataSets are 2 different ways as I figured late on and would have to go and change it to make the program run):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using GarageSales.Models;
namespace GarageSales.Data
{
public class GarageSalesContext: DbContext
{
public GarageSalesContext (DbContextOptions<GarageSalesContext> options)
: base(options)
{
}
public DbSet<Car> Cars { get; set; }
public DbSet<PaymentPlan> PaymentPlans { get; set; }
public DbSet<SalesMan> SalesMen { get; set; }
public DbSet<GarageSales.Models.Customer> Customer { get; set; }
public DbSet<GarageSales.Models.Duration> Duration { get; set; }
public DbSet<GarageSales.Models.Rental> Rental { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>().ToTable("Car");
modelBuilder.Entity<PaymentPlan>().ToTable("PaymentPlan");
modelBuilder.Entity<SalesMan>().ToTable("SalesMan");
modelBuilder.Entity<Duration>().ToTable("Duration");
modelBuilder.Entity<Rental>().ToTable("Rental");
modelBuilder.Entity<Customer>().ToTable("Customer");
}
}
}
If you need anymore information just ask

Related

Can't retrieve data from EF database

I have a simple application which should display the elements of a list, but it returns an empty array when debugging. I need this elements to be displayed dinamically. I'm wondering if the program is not working because of the following code...
StoreController.cs
using GetMed.Models;
namespace GetMed.Controllers
{
public class StoreController : Controller
{
GetMedEntities storeDB = new GetMedEntities();
//
// GET: /Store/
public ActionResult Index()
{
var categories = storeDB.Categories.ToList();
return View(categories);
}
}
}
SampleData.cs:
using System.Data.Entity;
namespace GetMed.Models
{
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
var categories = new List<Category>
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
};
}
}
}
GetMedEntities.cs
namespace GetMed.Models
{
public class GetMedEntities : DbContext
{
public DbSet<Category> Categories { get; set; }
}
}
Index.cs:
#model IEnumerable<GetMed.Models.Category>
#{
ViewBag.Title = "Index";
}
<h3>Browse Categories</h3>
<p>Select from #Model.Count() categories:</p>
<ul>
#foreach (var category in Model)
{
<li>#Html.ActionLink(category.Name, "Browse", new { category = category.Name })</li>
}
</ul>
If you look at your database, you will notice that there is no data in it. Look at your Seed method: what do you expect it to do?
After creating your data you have two more steps to do:
Adding it to a collection tracked by your DbContext
Saving it to the database
This results in these extra lines:
context.Categories.AddRange(categories);
context.SaveChanges();
Never initialize EF context gloablly, once it gonna hit you hard, believe me
When adding records to DB via EF you have to call
using (var context = new GetMedEntities)
{
// YOUR ADD ROUTINE GOES HERE
context.SaveChanges();
}
UPDATE
Change your class SampleData
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
//I STRICTLY RECOMMEND NOT TO PROVIDE CONTEXT AS A METHOD PARAMETER
//YOU HAVE TO WRITE PROPER DB LAYER TO DO SO
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();
}
}
But the simple solution is the following:
public class SampleData
{
public void SeedSampleData()
{
var context = new GedMedEntities();
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();

How to select only those records from collection which have relation with another table using Linq

Hi there I have 2 classes called SlownikRyzyk and Ryzyko. I create new variable called query. I want to insert to query only those records from SlownikRyzyk which have relation with the records in Class Ryzyko. I found the way how to do that by using pure linq but I want to know how to do this with lambda expression.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinqTraining
{
class SlownikRyzyk
{
public int Id { get; set; }
public string NazwaRyzyka { get; set; }
public static List<SlownikRyzyk> getListSlownikRyzyk()
{
List<SlownikRyzyk> listSlownikRyzyk = new List<SlownikRyzyk>
{
new SlownikRyzyk
{
Id=1,
NazwaRyzyka="Włamanie"
},
new SlownikRyzyk
{
Id=2,
NazwaRyzyka="Napad"
},
new SlownikRyzyk
{
Id=3,
NazwaRyzyka="Pożar"
},
new SlownikRyzyk
{
Id=4,
NazwaRyzyka="Zepsute zamki"
}
};
return listSlownikRyzyk;
}
}
class Ryzyko
{
public int Id { get; set; }
public string Opis { get; set; }
public int SlownikRyzykId { get; set; }
public static List<Ryzyko> getListRyzyko()
{
List<Ryzyko> listRyzyko = new List<Ryzyko>
{
new Ryzyko
{
Id=11,
Opis="Pożar piwnicy może grozić stratą wielu ton papieru",
SlownikRyzykId=3
},
new Ryzyko
{
Id=12,
Opis="Ktoś może zatrzasnąć się w pokuju",
SlownikRyzykId=0
},
new Ryzyko
{
Id=14,
Opis="Ktoś może napaść na kase",
SlownikRyzykId=0
},
new Ryzyko
{
Id=17,
Opis="Przez włamanie do biur mogą zostać wykradzione pufne dane frimy",
SlownikRyzykId=1
}
};
return listRyzyko;
}
}
class Program
{
static void Main(string[] args)
{
var query = from r in Ryzyko.getListRyzyko()
from s in SlownikRyzyk.getListSlownikRyzyk()
where s.Id == r.SlownikRyzykId
select s;
foreach (var a in query)
{
Console.WriteLine(a.NazwaRyzyka);
}
}
}
}
Try like this
var query=Ryzyko.getListRyzyko().
Join(SlownikRyzyk.getListSlownikRyzyk(),
r=>r.SlownikRyzykId,
s=>s.Id,
(r,s)=> new {R=r,S=s} )

How should I reassign many-to-many child relationships in Code First Entity Framework?

I can assign a child collection to a new parent object and on save the relationships are saved as expected. However, if the parent object already exists and I try the same, the new relationships I would expect to be created are not, and the old relations are still there.
Is the only way for me to do such a change to first work out the items that are being removed/added and then call Remove() and Add() on each? Or, is there something I'm missing in the below code;
public class Tag
{
public int TagId { get; set; }
public virtual ICollection<Location> Locations { get; set;}
}
public class Location
{
public int LocationId { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tests()
{
public void Create()
{
db.Locations.Add(new Location { Tags = db.Tags.Where(p => p.TagId == 2)}).ToList();
db.SaveChanges() // correctly saves the new location with TagId 2 attached
}
public void Edit()
{
var location = db.Locations.Single(p => p.LocationId == 1);
location.Tags = db.Tags.Where(p => p.TagId == 1).ToList();
db.Entry(location).State = EntityState.Modified;
db.SaveChanges(); // TagId 2 still attached, rather than TagId 1
}
}
You need a third table that links tag and location, containing the id of the two tables you'r trying to link, that's a database law, you cannot have an infinit and variable number of foreign keys in each of your tables.
The collection needs to have Clear() called on it.
public void Edit()
{
var location = db.Locations.Single(p => p.LocationId == 1);
location.Tags.Clear(); // added this line
location.Tags = db.Tags.Where(p => p.TagId == 1).ToList();
db.Entry(location).State = EntityState.Modified;
db.SaveChanges(); // TagId 1 now correctly attached
}
From MSDN;
Clear does the following:
Sets the IsLoaded flag to false.
Removes all entities from the collection.
Detaches relationships between removed entities and the
owner of the EntityCollection from the ObjectStateManager.
Removes the owner of the EntityCollection from the related
entities.
I've just run your tests and the behaviour is slightly different here (EF 6.1.3):
If you don'tcall Clear() then the new tags will be added to the collection. However, if there is an already existing tag an DbUpdateException is thrown.
If you call Clear() then only new tags will be associated to the location.
Therefore using Clear() is usually the right thing to do.
See the sample code below:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public class Location
{
[Key]
public int LocationId { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
[Key]
public int TagId { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class TagLocsDbContext : DbContext
{
public virtual DbSet<Tag> Tags { get; set; }
public virtual DbSet<Location> Locations { get; set; }
}
class DbInitializer : DropCreateDatabaseAlways<TagLocsDbContext>
{
protected override void Seed(TagLocsDbContext context)
{
base.Seed(context);
context.Tags.Add(new Tag() { });
context.Tags.Add(new Tag() { });
context.Tags.Add(new Tag() { });
context.Tags.Add(new Tag() { });
}
}
public class Tests
{
public void Create()
{
using (var db = new TagLocsDbContext())
{
db.Locations.Add(new Location { Tags = db.Tags.Where(p => p.TagId == 2).ToList() });
db.SaveChanges(); // correctly saves the new location with TagId 2 attached
}
}
public void Edit(bool clear)
{
using (var db = new TagLocsDbContext())
{
var location = db.Locations.Single(p => p.LocationId == 1);
if (clear) location.Tags.Clear();
location.Tags = db.Tags.Where(p => p.TagId == 1).ToList();
db.SaveChanges(); // if Clear ran locations = {1}, otherwise it is {1,2}
}
}
public void EditWithConflict()
{
using (var db = new TagLocsDbContext())
{
var location = db.Locations.Single(p => p.LocationId == 1);
location.Tags = db.Tags.ToList();
db.SaveChanges(); //Conflict - will throw an exception
}
}
}
class Program
{
static void Main(string[] args)
{
var initializer = new DbInitializer();
Database.SetInitializer(initializer);
var tests = new Tests();
tests.Create();
PrintLocation("After create: ", 1);
tests.Edit(false);
PrintLocation("After edit without clear: ", 1);
tests.Edit(true);
PrintLocation("After edit with clear: ", 1);
try
{
tests.EditWithConflict();
PrintLocation("After edit with clear: ", 1);
}
catch (DbUpdateException exc)
{
Console.WriteLine("Exception thrown : {0}",exc.Message);
PrintLocation("After edit with conflicting tags: ", 1);
}
Console.ReadLine();
}
private static void PrintLocation(string afterCreate, int i)
{
Console.WriteLine(afterCreate);
using (var db = new TagLocsDbContext())
{
var location = db.Locations.Single(a => a.LocationId == i);
var tags = string.Join(",", location.Tags.Select(a => a.TagId));
Console.WriteLine("Location {0} : Tags {1}", location.LocationId, tags);
}
}
}
}

Updating an entity in Entity Framework which contains lists of other entities

I'm trying to update objects in Entity Framework and I'd like to know what the best way of updating Entities that contain a List of other Entities.
Consider the following example:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EntityFrameworkUpdateSketch
{
public class A
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None)]
public int Akey {get;set;}
public string Aname { get; set; }
public virtual List<B> Blist {get;set;}
public A()
{
Blist = new List<B>();
}
}
public class B
{
public virtual A owner { get; set; }
[ForeignKey("owner")]
[Key, Column(Order = 0)]
public int Akey { get; set; }
[Key, Column(Order = 1)]
public int Order { get; set; }
public string Bname { get; set; }
}
public class Database: DbContext
{
public DbSet<A> As { get; set; }
public DbSet<B> Bs { get; set; }
}
public class Program
{
static void Main(string[] args)
{
// Make a new object
using (Database db = new Database())
{
A intodb = new A();
intodb.Akey = 1;
intodb.Aname = "Name of A object";
intodb.Blist.Add(new B() { Bname = "Name of B object one",Order=1 });
intodb.Blist.Add(new B() { Bname = "Name of B object two",Order=2 });
db.As.Add(intodb);
db.SaveChanges();
}
// Update the object in database
using (Database db = new Database())
{
// Imagine I got "update" from somewhere else
A update = new A();
update.Akey = 1;
update.Aname = "New Name of A object";
update.Blist.Add(new B() { Bname = "New Name of B object one" ,Akey=1, Order=1});
update.Blist.Add(new B() { Bname = "New Name of B object two", Akey = 1, Order = 2 });
update.Blist.Add(new B() { Bname = "A whole new object 3", Akey = 1, Order = 3 });
db.Entry<A>(update).State = EntityState.Modified;
db.SaveChanges();
}
}
}
}
I have an object "A" that contains a List as a property.
In the first half of my demonstration program I create a new object of type A and then store it in the database.
In the second half, I make a new object called A and I want to update the object in the database with new values- I want to change the B names and I want to add a new B object to the list.
This works for changing A , but the subcategories B don't work- they don't have new names.
The reason I'm trying to do this is because I'm trying to write a PUT method for a MVC WebAPI controller that stores its data in Entity Framework. I'm getting a new object passed in to my PUT action and I want to replace an existing object in the database.
I can't delete A and re add it (although this does work) because this breaks foreign keys- I have cascading deletes in my "real" solution that removes references elsewhere if I delete my A object.
You don't need to know anything about WebAPI or PUT to answer this question.
Here is a program that works, but could do with improving. All this program does now is delete all B objects in the database that belong to A, then re-add. This works but it seems bad. Any improvements?
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EntityFrameworkUpdateSketch
{
public class A
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None)]
public int Akey {get;set;}
public string Aname { get; set; }
public virtual List<B> Blist {get;set;}
public A()
{
Blist = new List<B>();
}
}
public class B
{
public virtual A owner { get; set; }
[ForeignKey("owner")]
[Key, Column(Order = 0)]
public int Akey { get; set; }
[Key, Column(Order = 1)]
public int Order { get; set; }
public string Bname { get; set; }
}
public class Database: DbContext
{
public DbSet<A> As { get; set; }
public DbSet<B> Bs { get; set; }
}
public class Program
{
static void Main(string[] args)
{
// Make a new object
using (Database db = new Database())
{
A intodb = new A();
intodb.Akey = 1;
intodb.Aname = "Name of A object";
intodb.Blist.Add(new B() { Bname = "Name of B object one",Order=1 });
intodb.Blist.Add(new B() { Bname = "Name of B object two",Order=2 });
db.As.Add(intodb);
db.SaveChanges();
}
// Update the object in database
using (Database db = new Database())
{
// Imagine I got "update" from somewhere else
A update = new A();
update.Akey = 1;
update.Aname = "New Name of A object";
update.Blist.Add(new B() { Bname = "New Name of B object one" ,Akey=1, Order=1});
update.Blist.Add(new B() { Bname = "New Name of B object two", Akey = 1, Order = 2 });
update.Blist.Add(new B() { Bname = "A whole new object 3", Akey = 1, Order = 3 });
db.Entry<A>(update).State = EntityState.Modified;
// Clear all existing B objects attached to the updated object
var query = from c in db.Bs.AsEnumerable() where c.Akey==update.Akey select c;
foreach (var z in query)
{
db.Bs.Remove(z);
}
// Readd B objects
foreach (var i in update.Blist)
{
db.Bs.Add(i);
}
db.SaveChanges();
}
}
}
}

Unable to perform a not-in

I have a two objects, one AnotherList that contains an array of ints and the other MyFolder that contains an array of objects FolderItem that contains an array of objects ItemKeyword that have two strings (in a key-value-pair style).
I want to return a List<FolderItem> from MyFolder that are not referenced in the AnotherList. I can get a list of items that are in the list and have included the Linq for that at the bottom.
I have been fighting with .Contains and .Except extensions all day but keep getting errors. I'm hoping that this is easy for someone.
This is a case where code speaks a thousand words so here it is.
The Linq query at the end returns only one FolderItem at the moment folderItemID=25.
I need it to return all the FolderItems folderItemID=26,27,28 instead.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
namespace temp
{
class MyFolder
{
public FolderItem[] items { get; set; }
}
class FolderItem
{
public int folderItemID { get; set; }
public ItemKeyword[] keywords { get; set; }
}
class ItemKeyword
{
public string key { get; set; }
public string value { get; set; }
}
class AnotherList
{
public AnotherListItem[] items { get; set; }
}
class AnotherListItem
{
public int dataID { get; set; }
}
public class TestingClass
{
public static void mainApp()
{
AnotherList List1 = new AnotherList()
{
items = new AnotherListItem[]{
new AnotherListItem(){dataID=1},
new AnotherListItem(){dataID=2},
new AnotherListItem(){dataID=3}
}};
MyFolder List2 = new MyFolder()
{
items = new FolderItem[]
{
new FolderItem()
{
folderItemID=25, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="1"},
new ItemKeyword(){key="description", value="some text"},
}
},
new FolderItem()
{
folderItemID=26, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="4"},
new ItemKeyword(){key="description", value="some other text"},
}
},
new FolderItem()
{
folderItemID=27, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="9"},
new ItemKeyword(){key="description", value="even more other text"},
}
},
new FolderItem()
{
folderItemID=28, keywords= new ItemKeyword[]
{
new ItemKeyword(){key="dataID", value="12"},
new ItemKeyword(){key="description", value="3"},
}
}
}};
List<FolderItem> res = (from someItems in List2.items
from itemKeywords in someItems.keywords
join otherItems in List1.items on itemKeywords.value equals otherItems.dataID.ToString()
where itemKeywords.key == "dataID"
select someItems).ToList<FolderItem>();
}
}
}
First grab all of the IDs that we don't want and stick them into a set for fast searching:
var badIDs = new HashSet<int>(List1.items.Select(item => item.dataID));
Then get all of the folders where they are not contained in that set:
var goodFolders = List2.items.Where(folder =>
!badIDs.Contains(folder.folderItemID));
Try using the Any extension method. You can confidently copy and paste the code below since it is meant to work with the code you provided...
List<FolderItem> res = List2.items.Where(x => !List1.items.Any(y => x.keywords.FirstOrDefault(z => z.key == "dataID").value == y.dataID.ToString())).ToList();
var res = List2.items.Where(fi => !List1.items.Any(al =>
al.dataID.ToString() == fi.keywords.Single(k => k.key == "dataID").value));
Assuming a FolderItem only has one ItemKeyword with key="dataID".

Categories

Resources