Entity Framework objects being duplicated in the database - c#

I am working with Entity Framework (code first) for the first time and I have a little problem.
I have a class called Taxi & one called Driver
Taxi has a reference to the Driver, you can see both classed below
public partial class Taxi
{
public Taxi()
{
}
public int TaxiId { get; set; }
public Driver Driver { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Color Colour { get; set; }
public string NumPlate { get; set; }
public int MaxPassengers { get; set; }
}
public partial class Driver
{
public Driver()
{
}
public int DriverId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string HomePhone { get; set; }
public string MobilePhone { get; set; }
public DateTime JoinedFirm { get; set; }
}
And I am saving the changed Taxi like this:
using (var db = new DataModel())
{
db.Configuration.ProxyCreationEnabled = false;
db.Taxis
.Where(x => x.TaxiId == CurrenltySelectedTaxi.TaxiId)
.ToList()
.ForEach(x =>
{
x.Make = CurrenltySelectedTaxi.Make;
x.Model = CurrenltySelectedTaxi.Model;
x.NumPlate = CurrenltySelectedTaxi.NumPlate;
x.Colour = CurrenltySelectedTaxi.Colour;
x.MaxPassengers = CurrenltySelectedTaxi.MaxPassengers;
x.Driver = CurrenltySelectedTaxi.Driver;
});
db.SaveChanges();
}
My problem is that the Driver gets duplicated the in database every time I save a taxi.
You can see the database here:
Can someone point me in the right direction,
Thanks
EDIT:
The drivers are in a combo box and are selected like this
private void cmbTaxiDriver_SelectedIndexChanged(object sender, EventArgs e)
{
using (var db = new DataModel())
{
db.Configuration.ProxyCreationEnabled = false;
Driver listSelected = (Driver) cmbTaxiDriver.SelectedItem;
CurrenltySelectedTaxi.Driver = db.Drivers.Where(x => x.DriverId == listSelected.DriverId).ToArray()[0];
}
}
And the combo box is populated like this:
listDrivers.Items.AddRange(db.Drivers.ToArray());

The only thing that I can possibly find based on the content you have provided is that CurrenltySelectedTaxi.Driver is a detached or new driver. Be careful to ensure that the object pointed to by CurrenltySelectedTaxi.Driver is an attached driver record.
An option you can do to help determine the status of that record is to put a breakpoint on that line and then look at the DbEntry record status.

Your design doesn't create a relationship between Taxi and Driver that's going to translate to a database. Try something like this:
public partial class Taxi
{
public Taxi()
{
}
public int TaxiId { get; set; }
public int DriverId {get; set; }
public virtual Driver Driver { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Color Colour { get; set; }
public string NumPlate { get; set; }
public int MaxPassengers { get; set; }
}
You may also want to add the following to the Driver object:
public virtual IEnumerable<Taxi> Taxis { get; set; }

So it turns out my issue is because i followed the tutorial on MSDN that says to recreate your context EVERYTIME you use it. Although this 'may' be good practice, in this instance it caused the problem.
If I make one context for the entire class it works as expected/

Related

Automapper executes without error, but no data being copied from source to destination

I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));

Invoking child nodes Entity Framework Core

I'm new into this sort of object programming, do you mind helping me?
I have to invoke the child nodes, but specific fields, but I can't figure out how to do that. I have already looked into a huge number of places, but it doesn't seem to work.
For example, I want just the FirstName in the RepunicAccount, and all the other info from RepunicAccountType, or anything like it.
My DbContext:
public class RepunicContext : DbContext
{
public virtual DbSet<RepunicAccount> RepunicAccount { get; set; }
public virtual DbSet<RepunicAccountType> RepunicAccountType { get; set; }
protected override void OnConfiguring (DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer ("Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Repunic;Data Source=DESKTOP- 6I8LD45\\SQLEXPRESS_ERICH");
}
public RepunicContext (DbContextOptions<RepunicContext> options) :base (options)
{ }
public RepunicContext () { }
}
My model class:
public class RepunicAccount
{
public int ID { get; set; }
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[ForeignKey ("ID_Type")]
public int? ID_Type { get; set; }
public ICollection<RepunicAccountType> TipoConta { get; set; }
public DateTime? DataCadastro { get; set; } = DateTime.Now;
public DateTime? DataAlteracao { get; set; } = DateTime.Now;
}
My child node class:
public class RepunicAccountType
{
[Key]
public int ID_Type { get; set; }
public string Descricao { get; set; }
public DateTime DataCadastro { get; set; } = DateTime.Now;
public DateTime DataAlteracao { get; set; } = DateTime.Now;
}
I have a repository, that is where I do my coding, before putting into the controller, it's pretty much the same in every place, but I'm going to show the example that I'm trying to use in both places.
public IEnumerable<RepunicAccount> GetAllByIDType ()
{
var data = db.RepunicAccount.Where (a => a.ID_Type != null)
.Include (p => p.types);
var type = db.RepunicAccountType.OrderBy (b => b.Descricao);
return data.ToList();
}
The problem is: I dont know how to invoke specific items nor make anything else other thanToList();`
So, what should I do? If there is any more info that I can send, just ask me.
I would love to comment however, I do not have the required reputation to do so.
Since you are new to the subject please be sure to follow the documentation.
EF Core Documentation
I also have created a youtube video for getting started that I would suggest you take a few minutes to view.
Video on EF Core
in short, you need a DBContext and your Models. You then can start a query for data and returning in the format you wish. Like so:
using (var context = new RepunicContext())
{
var accounts = context.RepunicAccounts.ToList();
}
accounts will then have a list of every account that you can iterate through. Hope this helps.

How to add many to many relationship through Entity Framework 6, in code?

Hello I have following classes/Models mapped to database using Code-First
public class Speaker
{
public int Id { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public virtual ICollection<SpeakerCertification> Certifications { get; set; }
}
public class Certification
{
public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<SpeakerCertification> Speakers { get; set; }
}
public class SpeakerCertification
{
public int Id { get; set; }
public int SpeakerId { get; set; }
public int CertificationId { get; set; }
public virtual Speaker Speaker { get; set; }
public virtual Certification Certifications { get; set; }
}
The certification table is already populated with some data. When speaker information is added, the speakers certification must be added as well (which can be chosen through checkboxes). Now I have to add this information to the database. I have written following code and stuck (_ctx is the dbContext). I require the speakerId for speakerCertification table but the speaker is not yet added in the database. The requirement is speakerId must be an identity field. How can I achieve this? The string array selectedCertifications contain the certifications selected when adding the speaker
public bool AddSpeaker(Entities.Speaker speaker, string[] selectedCertifications)
{
if (selectedCertifications != null)
{
SpeakerCertification speakerCertification = new SpeakerCertification();
speaker.Certifications = new List<SpeakerCertification>();
foreach (var certificate in selectedCertifications)
{
var certificationToAdd = _ctx.Certifications.Find(int.Parse(certificate));
speakerCertification.CertificationId = certificationToAdd.Id;
//speakerCertification.SpeakerId
speaker.Certifications.Add(speakerCertification);
}
}
_ctx.Speakers.Add(speaker);
_ctx.SaveChanges();
return true;
}
Sorry for troubling those who went through the question, there was almost no problem at all. I was just too silly to miss it. I forgot the magic of Entity Framework. I implemented the add function in following way
public bool AddSpeaker(Entities.Speaker speaker, string[] selectedCertifications)
{
if (selectedCertifications != null)
{
SpeakerCertification speakerCertification = new SpeakerCertification();
speaker.Certifications = new List<SpeakerCertification>();
foreach (var certificate in selectedCertifications)
{
if (certificate.CompareTo("false")!=0)
{
var certificationToAdd = _ctx.Certifications.Find(int.Parse(certificate));
speakerCertification = new SpeakerCertification();
speakerCertification.CertificationId = certificationToAdd.Id;
speaker.Certifications.Add(speakerCertification);
}
}
}
_ctx.Speakers.Add(speaker);
_ctx.SaveChanges();
return true;
}

C# Linq search inside object linked property

i'm trying to do some search inside some attributes of my object set but i'm getting some trouble on the right way to mount my linq query, i have my VT_Video class which has its attributes and some linked objects
public partial class VT_Video
{
public int ID { get; set; }
public string title { get; set; }
public string description { get; set; }
public virtual ICollection<VT_VideoTag> VT_VideoTag { get; set; }
}
public partial class VT_VideoTag
{
public int ID { get; set; }
public int tagID { get; set; }
public int videoID { get; set; }
public virtual VT_Tag VT_Tag { get; set; }
public virtual VT_Video VT_Video { get; set; }
}
public partial class VT_Tag
{
public int ID { get; set; }
public string name { get; set; }
public virtual ICollection<VT_VideoTag> VT_VideoTag { get; set; }
}
What i want to accomplish is search a user given word inside my Video collection by VT_Video.title, VT_Video.description and also by VT_Video.VT_VideoTag.VT_Tag.name, what i managed to do so far is only search the title and description:
var myVideos = db.VT_Video.Include("VT_VideoTag")
.Include("VT_VideoTag.VT_Tag")
.Where(vid =>
vid.descricao.Contains(strBusca) ||
vid.titulo.Contains(strBusca)).ToList();
Now, i know i can do what i want with some foreach and extra code but i wondered if it would be possible to do it using linq and also keep my code clean.
Thanks.
I have not worked with LINQ to SQL much, but it seems like .Any() would satisfy your requirement:
var myVideos = db.VT_Video.Include("VT_VideoTag")
.Include("VT_VideoTag.VT_Tag")
.Where(vid =>
vid.descricao.Contains(strBusca) ||
vid.titulo.Contains(strBusca) ||
vid.VT_VideoTag.Any(tag => tag.name.Contains(strBusca))).ToList();
Notice I added this clause:
vid.VT_VideoTag.Any(tag => tag.name.Contains(strBusca))
Which returns true if any tag in the collection has a name that contains your search string.

Updating List<T> in DbContext

I have a Model like this
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<string> SolvedBy { get; set; }
}
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
}
and then Controller like this. But I cannot update the List "SolvedBy", the next time I step through with the debugger, the list is still empty.
[HttpPost]
public string Index(string flag = "", int id=0)
{
Challenge challenge = db.Challenges.Find(id);
if (flag == challenge.Flag)
{
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<string>();
}
chall.SolvedBy.Add(User.Identity.Name);
db.Entry(chall).State = EntityState.Modified;
db.SaveChanges();
//congrats, you solved the puzzle
return "got it";
}
else
{
return "fail";
}
}
is there any way around it to make a list of strings kept in the database?
EF don't know how to store an array in database table so it just ignore it. You can create another table/entity or use XML/JSON to store the list. You can serialize the list before saving and deserialize it after loading from database
A List<T> in a model would normally map to a second table, but in your DbContext you only have a single table. Try adding a second table.
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
public DbSet<Solution> Solutions {get; set;}
}
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<Solution> SolvedBy { get; set; }
}
public class Solution
{
public int ID { get; set; }
public string Name { get; set; }
}
Then your controller can use code along the lines of...
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<Solution>();
}
chall.SolvedBy.Add(new Solution {Name=User.Identity.Name});
None of the above has been tested and I may have made some mistakes there, but the general principle I want to illustrate is the fact that you need another table. The List<T> represents a JOIN in SQL.

Categories

Resources