Entity Framework Null reference exception when adding to bridge tables - c#

I'm using Entity Framework with an MVC5 Application and currently I am trying to save some form data that touches multiple tables in my database. When I am adding data to the tables it seems to be working fine but once I hit the bridge tables I am getting a null ref exception that, to me, doesn't make sense.
I am new to programming so any help would be greatly appreciated.
public void RegisterNewUser(IDCRegisterViewModel model)
{
//
string fullAddress = model.AddressLine1 + "\n" + model.AddressLine2 + (string.IsNullOrEmpty(model.AddressLine2) ? "" : "\n" ) + model.City + ", " + model.State + " " + model.Zip + "\n" + model.Country;
using (var AuthContext = new InfoKeeperEntities1())
{
AuthContext.Locations.Add(new Location {
Line1 = model.AddressLine1,
Line2 = model.AddressLine2,
City = model.City,
State = model.State,
Zip = model.Zip,
Country = model.Country,
UserID = model.UserID,
FullAddr = fullAddress
});
AuthContext.ProfileDatas.Add(new ProfileData
{
UserID = model.UserID,
UACC = model.UACC,
isRecCenter = model.IsRecCenter,
isCustAdmin = model.IsCustAdmin
});
//Add to bridge tables for user/dept and group/dept
List<Department> deptList = new List<Department>();
foreach (var ID in model.GroupIDs)
{
deptList.Add(AuthContext.Departments.FirstOrDefault(x => x.ID == ID));
}
foreach (var department in deptList)
{
//NULL REF EXCEPTION HERE
AuthContext.AspNetUsers.FirstOrDefault(x => x.Id == model.UserID).Departments.Add(department);
foreach (var groupID in model.GroupIDs)
{
AuthContext.Groups.FirstOrDefault(x => x.ID == groupID).Departments.Add(department);
}
}
}
}

If you turn the LazyLoadingEnabled and ProxyCreationEnabled off you always face with an error because of using Department after FirstorDefault Query and EntityFramework doesn't include it for AppUsers, You have the same problem with adding the department to the Group. So you must include the Department first for both of them.
put using System.Data.Entity; in the very first of the codes.
change the code statement to this:
public void RegisterNewUser(IDCRegisterViewModel model)
{
string fullAddress = model.AddressLine1 + "\n" + model.AddressLine2 + (string.IsNullOrEmpty(model.AddressLine2) ? "" : "\n" ) + model.City + ", " + model.State + " " + model.Zip + "\n" + model.Country;
using (var AuthContext = new InfoKeeperEntities1())
{
AuthContext.Locations.Add(new Location {
Line1 = model.AddressLine1,
Line2 = model.AddressLine2,
City = model.City,
State = model.State,
Zip = model.Zip,
Country = model.Country,
UserID = model.UserID,
FullAddr = fullAddress
});
AuthContext.ProfileDatas.Add(new ProfileData
{
UserID = model.UserID,
UACC = model.UACC,
isRecCenter = model.IsRecCenter,
isCustAdmin = model.IsCustAdmin
});
//Add to bridge tables for user/dept and group/dept
List<Department> deptList = new List<Department>();
foreach (var ID in model.GroupIDs)
{
deptList.Add(AuthContext.Departments.FirstOrDefault(x => x.ID == ID));
}
var user = AuthContext.AspNetUsers.Include("Departments").FirstOrDefault(x => x.Id == model.UserID);
foreach (var department in deptList)
{
user.Departments.Add(department);
foreach (var groupID in model.GroupIDs)
{
var group = AuthContext.Groups.Include("Departments").FirstOrDefault(x => x.ID == groupID);
group.Departments.Add(department);
}
}
}
}
Tip: Don't forget to make a new instance of List<Depatment> in the constructor of AspNetUsers and Groups:
public class ApplicationUser
{
Public ApplicationUser()
{
this.Departments = new List<Department>();
}
}
public class Group
{
Public Group()
{
this.Departments = new List<Department>();
}
}

Related

Join with comma separated values in SQL Server [Linq]

I am writing a question with LINQ to join li. How do I get the result table with 3 table combinations? I have to combine the table in one line.
Any ideas?
Peole
---------------
Id | 1 Id |2
Name | David Name |Ameyy
Surname| David1 Surname |Ameyy2
Appointment
---------------
Id |19
PeopleId |1
Subject |description
Participant
---------------
Id |1 Id |2
AppointmentId |19 AppointmentId |19
PeopleId |1 PeopleId |2
Result
----------------------------------
Id | 1
Subject | Subject
Participant| David David1, Ameyy Ameyy2
Linq query;
IQueryable<AppointmentPoolModel> query = db.Randevu.Join(db.Kisi,
appointment => appointment .TALEPEDENKISI,
people=> people.ID,
(appointment , people)
=> new AppointmentPoolModel
{
Id = appointment.ID,
Subject = appointment.Subject,
Note = appointment .NOTLAR,
NameSurname = people.Name+ " " + people.Surname,
RequestedId = people.ID,
//Participan = string.Join(",", )
});
var result = query.OrderBy(appointment => randevu.AppointmentStartDate).ToList();
You can try this.
var qPeoples = Participants.Join(Peoples,
pr => pr.PeopleId,
pe => pe.Id,
(pr, pe) => new { Part = pr, People = pe });
var result = Appointments.Select(app => new
{
app.Id,
app.Subject,
Participant = String.Join(",", qPeoples.Where(q => q.Part.AppointmentId == app.Id)
.Select(s => new
{ FullName = String.Format( "{0} {1}"
, s.People.Name, s.People.Surname ) } ) )
}).ToList();
You should investigate step by step.
Here a example withtwo dedicated joins and a groupBy (which is missing in your case):
public class People
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public class Appointment
{
public int Id { get; set; }
public string Subject { get; set; }
}
public class Participation
{
public int Id { get; set; }
public int PeopleId { get; set; }
public int AppointmentId { get; set; }
}
static void Main(string[] args)
{
// Example-Data (Would have helped in this format ;))
List<People> people = new List<People>()
{
new People() { Id = 1, Surname = "David1", Name = "David"},
new People() { Id = 2, Surname = "Ameyy2", Name = "Ameyy"}
};
List<Appointment> appointments = new List<Appointment>()
{
new Appointment() { Id = 1, Subject = "description" }
};
List<Participation> participations = new List<Participation>()
{
new Participation() { Id = 1, PeopleId = 1, AppointmentId = 1 },
new Participation() { Id = 1, PeopleId = 2, AppointmentId = 1 }
};
Console.WriteLine("***** JOIN appointment to participation *****");
// At the beginning we want to join the table 'Appointment' with the n-to-n-Table "Participation".
var AppointmentsAndParticipations = appointments.Join
(
participations, // Other table to connect
a => a.Id, // Key in 1st table
p => p.AppointmentId, // Key in 2nd table
(a, p) => new { Appointment = a, PeopleId = p.PeopleId } // build new row
);
foreach (var item in AppointmentsAndParticipations)
{
// The result should be out appointment and the peopleId. We got "Appointment.Count*Participations.Count" rows
Console.WriteLine(item.Appointment.Id.ToString().PadLeft(5) + ", " + item.Appointment.Subject.PadLeft(15) + ", " + item.PeopleId);
}
Console.WriteLine("***** JOIN people *****");
// We need to join the people which belong to the Ids in participation
var AppointmentsAndPeople = AppointmentsAndParticipations.Join
(
people, a => a.PeopleId, // Similar to 1st join...
p => p.Id,
(a, p) => new { Appointment = a.Appointment, People = p }
);
foreach (var item in AppointmentsAndPeople)
{
Console.WriteLine(item.Appointment.Id.ToString().PadLeft(5) + ", " + item.Appointment.Subject.PadLeft(15) + ", " + item.People.Name + " " + item.People.Surname);
}
Console.WriteLine("***** Group the rows *****");
// Now we want to group the rows back to Appointment-Level. We group by Appointment and People will be out elements to be sum-up
var AppointmentPools = AppointmentsAndPeople.GroupBy
(
key => key.Appointment, // Select the 'column' which shall be the keys
group => group.People, // Select the 'column' which will be converted to a single value (like count, sum, max ..or in your case string.join())
(key, group) => new // Build the output object..
{
Id = key.Id,
Subject = key.Subject,
Participants = string.Join(", ", group.Select(s => s.Name + " " + s.Surname))
}
);
foreach (var item in AppointmentPools)
{
Console.WriteLine("Id: " + item.Id + ", Subject: " + item.Subject + ", Participants: " + item.Participants);
}
}

Using Linq to select multiple items per iteration?

Per iteration, this query creates an EmailRecipient for each populated address. Can it be done without the multiple iteration?
var addedRecipients = (from oldRecip in oldEmailRecipients
where !string.IsNullOrWhiteSpace(oldRecip.EmailAddress1)
select new EmailRecipient
{
UserName = oldRecip.UserName,
EmailAddress = oldRecip.EmailAddress1
}
).Union(from oldRecip in oldEmailRecipients
where !string.IsNullOrWhiteSpace(oldRecip.EmailAddress2)
select new EmailRecipient
{
UserName = oldRecip.UserName,
EmailAddress = oldRecip.EmailAddress2
});
You can use SelectMany extension method:
var addedRecipients = oldEmailRecipients.SelectMany(e=>
{
var result= new List<EmailRecipient>();
if(!string.IsNullOrWhiteSpace(e.EmailAddress1))
{
result.Add(new EmailRecipient
{
UserName = e.UserName,
EmailAddress = e.EmailAddress1
});
}
if(!string.IsNullOrWhiteSpace(e.EmailAddress2))
{
result.Add(new EmailRecipient
{
UserName = e.UserName,
EmailAddress = e.EmailAddress2
});
}
return result;
});
Update
The solution that I show above only works in Linq to Objects. Your comment suggest me you are using EF. A simple solution could be call AsEnumerable method before SelectMany to make the switch to Linq to Objects, but that could end harming your performance if you are not filtering your recipients first.
Another solution could be selecting only data that you need first from you server before of call SelectMany to not load other columns you don't need in this case:
...Where(...)
.Select(r=>new{UserName=r.UserName,
EmailAddress1=r.EmailAddress1,
EmailAddress2=r.EmailAddress2 })
.AsEnumerable()
.SelectMany(...);
Sticking with query syntax, and making sure to only process oldEmailRecipients items who have either a non-null/whitespace EmailAddress1 or a non-null/whitespace EmailAddress2:
var addedRecipients =
from oldEmail in oldEmailRecipients
let hasEmail1 = !string.IsNullOrWhiteSpace(oldEmail.EmailAddress1)
let hasEmail2 = !string.IsNullOrWhiteSpace(oldEmail.EmailAddress2)
where hasEmail1 || hasEmail2
let emailUserNameCombos = hasEmail1 && hasEmail2
? new[]
{
new {Email = oldEmail.EmailAddress1, oldEmail.UserName},
new {Email = oldEmail.EmailAddress2, oldEmail.UserName}
}
: hasEmail1
? new[] {new {Email = oldEmail.EmailAddress1, oldEmail.UserName}}
: new[] {new {Email = oldEmail.EmailAddress2, oldEmail.UserName}}
from emailUsername in emailUserNameCombos
select new EmailRecipient
{
UserName = emailUsername.UserName,
EmailAddress = emailUsername.Email
};
You can build an inline array to add both emails and flatten them out using SelectMany.
var addedRecipients = from oldRecip in oldEmailRecipients
let emails =
new[] {oldRecip.EmailAddress1, oldRecip.EmailAddress2}.Where(e => !string.IsNullOrWhiteSpace(e))
from email in emails
where emails.Any()
select new EmailRecipient
{
UserName = oldRecip.UserName,
EmailAddress = email
};
When your EmailRecipient has more than two email address then you could do this:
// Just building a pseudo dataclass
List<Recipient> oldEmailRecipients = Enumerable.Range(1, 10).Select(item => new Recipient()
{
Name = "Recipient" + item,
EmailAddress1 = "pseudo" + item + "#gmail.com",
EmailAddress2 = "pseudo" + (item + 1) + "#gmail.com",
//EmailAddress3 = "pseudo" + (item + 2) + "#gmail.com",
EmailAddress3 = "",
EmailAddress4 = "pseudo" + (item + 3) + "#gmail.com",
} ).ToList( )
// create anonymous object for each recipient and a list of valid adresses
var query = from mailRecipients in oldEmailRecipients
select new
{
Name = mailRecipients.Name,
Addresses = new List<string>()
{
mailRecipients.EmailAddress1,
mailRecipients.EmailAddress2,
mailRecipients.EmailAddress3,
mailRecipients.EmailAddress4
}.Where(item => string.IsNullOrEmpty( item ) == false )
};
// create an EmailRecipient for each valid combination
var final = from item in query
from address in item.Addresses
select new EmailRecipient
{
Name = item.Name,
Address = address
};

Dynamic Where Linq C#

I'm using System.Linq.Dynamic to make dinanmico where in my research. In the code below I try to filter by Funcao, but returns the error:
No property or field 'Funcao' exists in type 'ASO'
How do I filter by an alias of my Linq?
CODE
public static ResultadoListagemPadrao Grid(int iniciarNoRegistro, int qtdeRegistro, string orderna, string ordenaTipo, string filtro, int filtroID, UsuarioLogado usuarioLogado)
{
var where = "";
var id = 0;
if (filtroID > 0)
where += " FuncionarioID == " + filtroID.ToString();
else
{
if (int.TryParse(filtro, out id))
where += " ASOID == " + id.ToString();
if (filtro != null)
where += " Funcao.Contains(#0) ";
}
using (var db = new ERPContext())
{
var resultado = new ResultadoListagemPadrao();
resultado.TotalRegistros = db.ASO.Total(usuarioLogado.EmpresaIDLogada);
resultado.TotalRegistrosVisualizados = db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable().Where(where, filtro).Count();
resultado.Dados =
(from a in db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable()
select new
{
a.ASOID,
a.FuncionarioID,
Cliente = a.Funcionario.Cliente.Pessoa.Nome,
Setor = a.FuncionarioFuncao.Funcao.Setor.Descricao,
Funcao = a.FuncionarioFuncao.Funcao.Descricao,
Funcionario = a.Funcionario.Pessoa.Nome,
a.DtASO,
a.Status
})
.Where(where, filtro)
.OrderBy(orderna + " " + ordenaTipo)
.Skip(iniciarNoRegistro)
.Take(qtdeRegistro)
.ToArray();
return resultado;
}
}
Issue is this line db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable().Where(where, filtro)
Your class ASO doesn't have a property Funcao.
Try remove the Where on that line. Try this...
var resultado = new ResultadoListagemPadrao();
resultado.TotalRegistros = db.ASO.Total(usuarioLogado.EmpresaIDLogada);
var query = (from a in db.ASO.ToListERP(usuarioLogado.EmpresaIDLogada).AsQueryable()
select new
{
a.ASOID,
a.FuncionarioID,
Cliente = a.Funcionario.Cliente.Pessoa.Nome,
Setor = a.FuncionarioFuncao.Funcao.Setor.Descricao,
Funcao = a.FuncionarioFuncao.Funcao.Descricao,
Funcionario = a.Funcionario.Pessoa.Nome,
a.DtASO,
a.Status
})
.Where(where, filtro);
resultado.TotalRegistrosVisualizados = query.Count();
resultado.Dados = query
.OrderBy(orderna + " " + ordenaTipo)
.Skip(iniciarNoRegistro)
.Take(qtdeRegistro)
.ToArray();
return resultado;
Please in future translate your code.

How to solve This modify Controller?

Every Thing goes right ,I've all the values that make me get the new model with values to modify it but something goes wrong at the final step
and my model validation state is true
This is my post Controller
[HttpPost]
public ActionResult Edit(Problem problem, HttpPostedFileBase fileUpload)
{
Problem Edproblem = db.Problems.Find(problem.Id);
ViewBag.ATMId = new SelectList(db.ATMs, "Id", "AtmNumber", Edproblem.ATM.AtmNumber);
ViewBag.UserId = WebSecurity.GetUserId(User.Identity.Name);
ViewBag.ProblemTypeId = new SelectList(db.ProblemTypes, "Id", "Name", Edproblem.ProblemTypeId);
var bankId = from e in db.ATMs where e.Id == problem.ATMId select e;
ViewBag.BankId = new SelectList(db.Banks, "Id", "Name", bankId);
ViewBag.AreaId = new SelectList(db.Areas, "Id", "Name", db.Areas.Where(p => p.Id == Edproblem.ATM.AreaId));
ViewBag.GovId = new SelectList(db.Governates, "Id", "Name", Edproblem.ATM.Area.GovernateId);
Problem beforeEdit = db.Problems.AsNoTracking().First(p => p.Id == problem.Id);
if (ModelState.IsValid)
{
DateTime now = DateTime.Now;
if (!Directory.Exists(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/"))))
{
Directory.CreateDirectory(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/")));
}
if (!Directory.Exists(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/") + Edproblem.ATMId.ToString())))
{
Directory.CreateDirectory(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/") + Edproblem.ATMId.ToString()));
}
if (!Directory.Exists(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/") + Edproblem.ATMId.ToString() + now.ToString("/dd/"))))
{
Directory.CreateDirectory(Server.MapPath("~/UploadImages/" + now.ToString("yyyy_MM/") + Edproblem.ATMId.ToString() + now.ToString("/dd/")));
}
var image = WebImage.GetImageFromRequest();
if (fileUpload != null)
{
string fileName = fileUpload.FileName.ToString();
fileName = Guid.NewGuid().ToString() + fileName.Substring(fileName.LastIndexOf("."));
fileName = now.ToString("yyyy_MM/") + problem.ATMId.ToString() + "/" + now.ToString("dd/") + fileName;
if (fileUpload != null && fileUpload.ContentLength > 0)
fileUpload.SaveAs(Server.MapPath("~/UploadImages/" + image));
image.Save(Server.MapPath("/UploadImages/" + fileName));
problem.ImagePath = fileName;
}
else
{
if (problem.ImagePath == null)
{
var getPath = (from e in db.Problems
where e.Id == problem.Id
select e.ImagePath).ToList();
problem.ImagePath = getPath[0].ToString();
}
}
problem.UserId = WebSecurity.GetUserId(User.Identity.Name);
db.Entry(problem).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(problem);
}
This is Error as it appear exactly:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
You're loading a Problem object into variable beforeEdit, and there is no further use of it.
If you try to update the beforeEdit with the new data from the parameter, and save that one instead of the object returned from the view.

How do I navigate related entities from a stored procedure that is mapped to an entity

I have a complicated full-text search stored procedure that I have mapped to return an entity type. It won't allow me to navigate the references in the result though:
using (MyEntities kb = new MyEntities())
{
var results = from customer in kb.SearchCustomers("blabla") select new
{
CustomerName = customer.LastName + ", " + customer.FirstName,
RegionName = customer.Region.Name
};
}
This is throwing a null reference exception when referring to the customer.
We should check LastName and FirstName first. I think there are customers who don't have FirstName or Lastname.
using (MyEntities kb = new MyEntities())
{
var results = from customer in kb.SearchCustomers("blabla") select new
{
if(customer.LastName != null && customer.FirstName != null)
{
CustomerName = customer.LastName + ", " + customer.FirstName,
RegionName = customer.Region.Name
}
};
}

Categories

Resources