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);
}
}
Related
I currently have a list of items from an object. I send the list to another method where it is copied to a csv file. The problem that I have is that the items are being listed on the csv in alphabetical order instead of the order they were added. I there a way to keep the original order?
SampleDatalist.Add(new SampleDataViewModel
{
PlanID = Convert.ToString(allFields["AdditionalInfo-PlanDetails-planNumber"]),
SSN = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-ssn"]),
EmployeeNumber = "",
DivisionId = "",
FirstName = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-firstName"]),
MiddleName = "",
LastName = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-lastName"]),
StreetAddress = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-homeAddress1"]),
City = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-homeCity"]),
State = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-homeState"]),
PostalCode = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-homeZip"]),
HomePhone = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-homePhone"]),
OfficePhone = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-businessPhone"]),
Email = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-email"]),
DateOfBirth = Convert.ToString(allFields["AccountOwnerInfo-ContactInfo-dob"]),
DateOfHire = Convert.ToString(allFields["AdditionalInfo-PlanDetails-dateOfHire"]),
MaritalStatus = Convert.ToString(allFields["AdditionalInfo-PlanDetails-maritalStatus"])
});
WriteCSV(PCSDatalist, #"C:\Users\brand\Documents\New_PPT_" + dt + ".csv");
public void WriteCSV<T>(IEnumerable<T> items, string path)
{
Type itemType = typeof(T);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
using (var writer = new StreamWriter(path, true))
{
foreach (var item in items)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
}
}
}
From the code you show, the items in the list show be written in the order they were added.
However, the properties of each item will be written in alphabetical order -- because you specifically ask that they are : .OrderBy(p => p.Name). If you do not what this, remove that clause, and the properties will be written in the order they are defined in the class.
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>();
}
}
I have this data:Users
UserId Name
42 Abc
43 Pqr
44 lmn
45 xyz
Mappings:
MappingId User1 User2
1 42 43
2 42 44
3 43 44
I want to get all user that is user2 which is not in user 1 and so the output will be below considering above input:
Expected Output:
UserId Name
44 lmn
This is my query:
var data = (from user in context.Users
join mappng in context.Mappings on user.UserId equals mappng.User2
where mappng.User1 != mappng.User2
select new
{
Name = user.FirstName + " " + user.LastName,
UserId = user.UserId,
}).ToList();
But getting wrong output:
UserId Name
43 Pqr
44 lmn
44 lmn
Note: There is no foreign key relationship and so no navigation property.
Here's a solution to your problem in a console application. I used where !(..) to find those not in mappings User1. I'm not sure of other alternatives to this approach. But hope it helps.
class Program
{
static void Main(string[] args)
{
List<User> users = new List<User>()
{
new User() { UserId = 42, Name = "Abc" },
new User() { UserId = 43, Name = "Pqr" },
new User() { UserId = 44, Name = "lmn" },
new User() { UserId = 45, Name = "xyz" },
};
List<UserMapping> userMappings = new List<UserMapping>()
{
new UserMapping() { MappingId = 1, User1 = 42, User2 = 43},
new UserMapping() { MappingId = 2, User1 = 42, User2 = 44},
new UserMapping() { MappingId = 3, User1 = 43, User2 = 44},
};
var data = (from u in users
join m in userMappings on u.UserId equals m.User2
where !(from mm in userMappings
select mm.User1).Contains(u.UserId)
select u).Distinct();
foreach(var entry in data)
{
Console.WriteLine(entry.UserId + " " + entry.Name);
}
Console.ReadLine();
}
}
class User
{
public int UserId { get; set; }
public string Name { get; set; }
}
class UserMapping
{
public int MappingId { get; set; }
public int User1 { get; set; }
public int User2 { get; set; }
}
Output:
44 lmn
The LINQ posted compares User1 and User2 values of the same row by using mappng.User1 != mappng.User2, which isn't the wanted query. Try using !Any() as follow :
var data = (from user in context.Users
join mappng in context.Mappings on user.UserId equals mappng.User2
where !context.Mappings.Any(m => m.User1 == user.UserId)
select new
{
Name = user.FirstName + " " + user.LastName,
UserId = user.UserId,
}).Distinct().ToList();
Try this:
var data = (from map1 in context.Mappings
join map2 in context.Mappings
on map1.User2 equals map2.User1 into subMap
from sub in subMap.DefaultIfEmpty()
where sub == null
join user in context.Users on map1.User2 equals user.UserId
select new {
Name = user.FirstName + " " + user.LastName,
user.UserId,
}).Distinct().ToList();
Could you try this.
var data = (select user from context.Users where (from m2 in context.Mappings select m2.User2).Except(from m1 in context.Mappings select m1.User1).Contains(user.UserId) select new {Name=user.Name, UserId=user.UserId}).ToList();
I don't see the user.FirstName, user.LastName in example table.
So you can revise new object by yourself if this solution is work.
Try this code snipped.
var result = context.Mappings.Where(mapping1 => !context.Mappings.Select(mapping2 => mapping2.User1).Contains(mapping1.User2))
.Select(e=> e.User2).Distinct()
.Join(context.Users, arg => arg, user=> user.UserId,(arg,user) => user)
.ToList();
I've a table with over 100 column (including blobs) and I want to make a copy of object only with a few filled columns.
right now I'm doing it by selecting needed columns and doing a round-trip serialize and deserialize with Json.NET which is not efficient. what's the best way to handle this scenario?
BL.Case mCase;
BL.Case temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
mCase = Newtonsoft.Json.JsonConvert.DeserializeObject<BL.Case>(Newtonsoft.Json.JsonConvert.SerializeObject(temp));
Use AutoMapper.
Do something like this:
BL.Case mCase = null;
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
if (temp != null)
{
mCase = Mapper.DynamicMap<BL.Case>(temp);
}
Another solution that requires a bit more code (but might perform better) is to do the following:
In case you need a single item:
BL.Case mCase = null;
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}).FirstOrDefault(u => u.CaseID == CaseID);
if (temp != null)
{
mCase = new Case()
{
CaseID = temp.CaseID,
FirstName = temp.FirstName,
LastName = temp.LastName,
};
}
If you need multiple items:
var temp = db.Cases.Select(
xx => new
{
CaseID = xx.CaseID,
FirstName = xx.FirstName,
LastName = xx.LastName
}); //Here you can filter your query if you want using Where
var result = temp
.ToList() //This will actually execute the query on the database
.Select(x => new Case() //Now you can do this since now we are working on in-memory data
{
CaseID = x.CaseID,
FirstName = x.FirstName,
LastName = x.LastName
});
I am trying to get the value of manager in the sharepoint list and when the manager values are the same, i'm trying to add all the amounts then output the manager name and the sum.
Here are the entries in the sharepoint list
Manager Amount
1 1000
2 2000
3 3000
4 500
1 1500
2 2500
Then I should send an email that should have this output and return only the top 3 highest amounts:
Manager Amount
2 4500
3 3000
1 2500
Here is my CAML Query
camlQuery.ViewXml = " <Query><Where><And><IsNotNull><FieldRef Name='Manager' /></IsNotNull><IsNotNull><FieldRef Name='Amount' /></IsNotNull></And><OrderBy><FieldRef Name='Amount' Ascending='False' /></OrderBy></Where></Query> ";
And Here is my Code
double iSum = 0;
foreach (ListItem oListItem in collListItem)
{
FieldUserValue man = (FieldUserValue)oListItem["Manager"];
if(oListItem["Amount"].ToString() == null)
continue;
iSum += Convert.ToDouble(oListItem["Amount"].ToString());
Console.WriteLine("\nManager Name: " + man.LookupValue + " Amount: " + iSum.ToString());
message += "<tr>"
+ " <td class='pdetails'> " + man.LookupValue + "</td> "
+ " <td class='pdetails'> " + iSum.ToString() + "</td></tr> ";
}
Kindly help me in fixing my caml query and foreach loop and how to get the expected output which is the sum of the amounts per manager. Please and thanks.
I don't have SharePoint handy, so the list access code might not be quite right, but the rest of the code should do what you want.
ManagerSummary summary = new ManagerSummary();
foreach (ListItem oListItem in collListItem)
{
FieldUserValue managerValue = (FieldUserValue)oListItem["Manager"];
string managerId = managerValue.LookupId;
string managerName = managerValue.LookupValue;
double amount = Convert.ToDouble(oListItem["Amount"].ToString());
summary.AddValue(managerId, managerName, amount);
}
StringBuilder output = new StringBuilder();
output.AppendLine("<tr><th>Manager Name</th><th>Total</th></tr>");
foreach (var manager in summary.TopManagers(3))
{
output.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", manager.Name, manager.Total);
output.AppendLine();
}
Console.WriteLine(output.ToString());
class ManagerSummary
{
Dictionary<string, Manager> _managers = new Dictionary<string, Manager>();
public void AddValue(string managerId, string managerName, double amount)
{
if (_managers.ContainsKey(managerId))
{
_managers[managerId].Total += amount;
}
else
{
_managers[managerId] = new Manager { Id = managerId, Name = managerName, Total = amount };
}
}
public List<Manager> TopManagers(int count)
{
var managers = _managers.Values.ToList();
return managers.OrderByDescending(x => x.Total).Take(count).ToList();
}
}
class Manager
{
public string Id { get; set; }
public string Name { get; set; }
public double Total { get; set; }
public override string ToString()
{
return string.Format("{0,-20}{1,-10}", Name, Total);
}
}
You can use the LINQ GroupBy to handle the grouping of managers for you, as well as the summing of all of the ammounts within a group.
var query = collListItem.OfType<ListItem>()
.Select(item => new
{
Manager = (FieldUserValue)item["Manger"],
Amount = item["Amount"] as double?,
})
.GroupBy(item => item.Manager.LookupValue)
.Select(group => new
{
Manager = group.Key,
Amount = group.Sum(item => item.Amount),
})
.Select(group => string.Format(
#"<tr><td class='pdetails'>{0}</td>
<td class='pdetails'>{1}</td></tr>", group.Manager, group.Amount));
string message = string.Concat(query);