How to map child entities in a reusable manner? - c#

I need to map an EF entity to an entity more suitable for performing business logic operations. To do so, I am using this expression:
var phoneMapper = phone => new BasePhone
{
Id = phone.Id,
Number = phone.Number,
PhoneType = phoneTypeMapper(phone.PhoneType) //Pseudo-Code
}
In this example, the phone type class should have a mapping of its own:
var phoneTypeMapper = phoneType => new BasePhoneType
{
Id = phoneType.Id,
Name = phoneType.Name
}
I want to use phoneTypeMapper within the definition of phoneMapper, how can I do so? I know this is easy to do with a collection:
var phoneMapper = phone => new BasePhone
{
Id = phoneType.Id,
Name = phoneType.Name,
//Now a phone has many phone types
PhoneTypes = phone.PhoneTypes.Select(phoneTypeMapper)
}
Is there a way to do this for a non-enumerable property?
EDIT
I should also mention that I would like for this to not collapse the query until the parent query has collapsed. I.E. I want to just jam this into a select and not have it hit the database every time it needs to pull record status data.

Related

Add values in list from other API method

I have one list and in that list I am adding values based on class. See below for details.
result.ContactList = contactsResult.Item2.Select(x => new PrjContact() {
Id = x.ID,
UserId = x.UserId,
Name = xName,
Email = x.Email,
}).ToList();
Now I need to call one more API and pass this UserId in that API and get phone number for that user.
Then need to add that phone number in above list in result.ContactList.
I have tried in this way.
foreach (var user in contactsResult.Item2)
{
UserInfo = API.GetUserDetail(user.UserId);
result.ContactList.Select(x => new ProjectContactView()
{
Phone = UserInfo.PhoneNumber
});
}
But this is not working.
This doesn't do anything:
result.ContactList.Select(x => new ProjectContactView()
{
Phone = UserInfo.PhoneNumber
});
Sure, it iterates over result.ContactList and projects it into a new collection. But (1) you don't do anything with that collection and (2) it overwrites every object in that collection with an entirely new object that has only one property set.
For starters, if you want to modify result.ContactList then iterate over that:
foreach (var user in result.ContactList)
{
}
Then if the goal here is to use a property on user to fetch data and update user then just update user:
foreach (var user in result.ContactList)
{
var userInfo = API.GetUserDetail(user.UserId);
user.Phone = userInfo.PhoneNumber
}

CSV to Cascading Model using Entity Framework

I need to turn an automatic CSV file into multiple database columns using Entity Framework. It is set up so that each model has children. So that Animal contains a list of Types which contain a list of Classification. In this way Classification is a grandchild of Animal
Right now I have these three models that need to be filled by the CSV file. The file is formatted in the following way:
They are then pulled from the API into a Windows Desktop App as a cascading dropdown box. So far I've tried adding them to separate lists however that did not upload when using Entity Framework. The current way is to try to cascade down the list however I get an error
Sequence contains no events
Here is the portion of the code that I am having a problem with (had to edit due to work rules so classes are different):
var Animal = new List<AnimalModel>();
var lines = await ReadStreamAsync(new StreamReader(uploadModel.File.OpenReadStream()));
foreach(string l in lines)
{
Animal.Add(new AnimalModel
{
AnimalName = cells[0],
});
Animal.Last().Type.Add(new TypeModel
{
TypeName = cells[1],
});
Animal.Last().Type.Last().Classification.Add(new ClassificationModel
{
Type = Type.Last(),
ClassificationName = cells[2],
Color = cells[3],
Age = cells[4]
});
}
I resolved the issue. I needed to initialize the list within the code as I am not doing so within the model. The following worked:
var Animal = new List<AnimalModel>();
var lines = await ReadStreamAsync(new StreamReader(uploadModel.File.OpenReadStream()));
foreach(string l in lines)
{
Animal.Add(new AnimalModel
{
AnimalName = cells[0],
Type = new List<TypeModel>()
{
new TypeModel()
{
TypeName = cells[1]
}
}
});
And so on for the grandchild. I will have to clean this up as it is quite messy but this works for now.

How to properly (deep) map complex objects with C# LINQ?

I have a database with owner and vehicle tables with a one-to-many relationship. I want to get all vehicle details and map each owner to each vehicle but I must map the query to a BDO. Not sure on the LINQ syntax but I have the code below.
using (var databaseContext = new DBConnection()) {
var vehicles = (from Vehicle in databaseContext.Vehicles
select Vehicle);
return vehicles.Select(x => new VehicleBDO() {
Id = x.Id,
// ... more simple data types
Owner = new OwnerBDO(
x.Owner.Id,
x.Owner.Name)
}).ToList();
}
Creating a new ownerBDO as shown is giving me a MethodNotSupportedException with details:
Only parameterless constructors and initializers are supported in LINQ
to Entities
I'm used to Java and new to LINQ so have no idea how to do it properly, any help would be much appreciated.
It wants you to do something like this:
Owner = new OwnerBDO() { Id = x.Owner.Id, name = x.Owner.Name},
(I don't know the property names for OwnerBDO so I guessed.)

Create a new record with a specific owner without calling AssignRequest in CRM 2011

In our application, we create a few thousand phonecall records. Each phonecall should have a different owner, determined by a method named GetAnyAppropriateSystemUser(), which finds some random SystemUser based on some criteria.
In the code example below, we create a phonecall, and later use AssignRequest on it to specify its owner.
PhoneCall phoneCall = new PhoneCall();
//
// stuff to set up the new PhoneCall instance here; populate fields, etc...
//
// determine this phonecall's owner through some algorithm
Guid appropriateOwner = GetAnyAppropriateSystemUser();
Guid createdPhoneCallId = _serviceProxy.Create(phoneCall);
if (createdPhoneCallId != Guid.Empty)
{
AssignRequest phoneCallAssign = new AssignRequest();
phoneCallAssign.Assignee = new EntityReference(SystemUser.EntityLogicalName, appropriateOwner);
phoneCallAssign.Target = new EntityReference(PhoneCall.EntityLogicalName, createdPhoneCallId);
_serviceProxy.Execute(phoneCallAssign);
}
This works allright, but there are two calls, one to create, and one to assign. Is it ok to just set "ownerid" of the PhoneCall record before calling Create() method, thus eliminating the need to call an AssignRequest later? It seems to work, and I even found an example doing a similar thing in the SDK, as shown below.
SDK Sample: Roll Up Goal Data for a Custom Period Against the Target Revenue
// Create three goals: one parent goal and two child goals.
Goal parentGoal = new Goal()
{
Title = "Parent Goal Example",
RollupOnlyFromChildGoals = true,
ConsiderOnlyGoalOwnersRecords = true,
TargetMoney = new Money(300.0M),
IsFiscalPeriodGoal = false,
MetricId = new EntityReference
{
Id = _metricId,
LogicalName = Metric.EntityLogicalName
},
GoalOwnerId = new EntityReference
{
Id = _salesManagerId,
LogicalName = SystemUser.EntityLogicalName
},
OwnerId = new EntityReference
{
Id = _salesManagerId,
LogicalName = SystemUser.EntityLogicalName
},
GoalStartDate = DateTime.Today.AddDays(-1),
GoalEndDate = DateTime.Today.AddDays(30)
};
_parentGoalId = _serviceProxy.Create(parentGoal);
Although it seems to work, are there anything that we must be aware of if we set ownerid before creating the new record? Are there any differences?
Thank you very much in advance.
As you already found is allowed to set the ownerid when you create the record.
But is not possible to edit the owner of an existing record in the same way, in that case you must use the AssignRequest.
Check also this question:
ETL Software, can't retrieve owner of a contact

Entity Framework LINQ projection into custom type results in missing data

I have a many to many relationship between Contractors and SafetyCouncils. They are joined by a bridge table ContractorsSafetyCouncils which consists of ContractorId and SafetyCouncilId. These 2 columns form a composite key. This relationship is mapped correctly in EF4. The Contractor entity has the property:
public virtual ICollection<SafetyCouncil> SafetyCouncils
{
get;
set;
}
And the SafetyCouncil entity has the property:
public virtual ICollection<Contractor> Contractors
{
get;
set;
}
When accessing these properties via lazy loading from a single Contractor or SafetyCouncil entity, they work exactly as expected. But when accessing this relationship in a query:
from c in ContractorRepository.All()
where c.PQFs.Count() > 0
let psmAudits = c.PQFs.SelectMany(pqf => pqf.Audits)
let psmAudit = psmAudits.FirstOrDefault(audit => audit.CompletedDate == psmAudits.Max(a => a.CompletedDate))
let scsAudits = c.PQFs.SelectMany(pqf => pqf.SCSAudits)
let scsAudit = scsAudits.FirstOrDefault(audit => audit.CompletedDate == scsAudits.Max(a => a.CompletedDate))
select new MasterListItem()
{
AdministratorNotes = c.AdminFlags.Where(f => f.IsActive && f.ForPQF).Select(f => f.Text),
CanViewInfo = false,
ContractorName = c.ContractorName,
ContractorId = c.Id,
ContractorTaxId = c.TaxId,
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
PQFSubmitted = c.PQFs.Max(p => p.PQFInfo.SubmittedDate.Value),
PSMAuditId = psmAudit.Id,
PSMAuditComplete = psmAudit.CompletedDate,
PSMAuditStatus = psmAudit.Status.Description,
SCSAuditId = scsAudit.Id,
SCSAuditComplete = scsAudit.CompletedDate
};
The problem occurs with:
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
For every record the SafetyCouncilIds collection has 0 members, when based on the data in the database every record should have at least 1 SafetyCouncilId associated with it.
If I run the same query, but project into an anonymous type instead of the MasterListItem type, it works correctly. Why can't I project this query into my custom type?
Update:
My MasterListItem POCO contained the following properties:
public string SafetyCouncilIdsString
{
get;
set;
}
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb.Append(id);
sb.Append(",");
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb = sb.Append(id).Append(","); // <-- try this
// *or sb = sb.AppendFormat("{0},", id);*
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
I have two suggestions:
Try to isolate the the problem by removing any extra parts of the query.
Compare the two sql queries generated and find the differences.
Unfortunately, without access to your code or schema, I can't provide a better answer.
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.

Categories