foreach inside xdocument.add - c#-4.0

I have a class that has a dictionary field. I want to loop through every item of this class and create an xml document but inside this loop I want to loop through this dictionary properties and add the key values pairs.
I am looking for something that will do the following
foreach(Book bk in query)
{
ReturnData.Descendants("Books")
.FirstOrDefault().Add(new XElement("Book",
new XElement("Name", bk.BookName),
new XElement("Measure", bk.Measure,
.foreach(KeyValuePair<string, double> measure in bk.NewMeasures)
{
new XElement(measure.Key,measure.Value)
},
new XElement("Value", bk.PreviousValue))));
}
Return data already contains some XML, this is why I am adding to the Books descendants. It may already have other roots such as videos, games etc.
Appreciate any thoughts on this.

First of all, I would query for the first book outside the loop:
var book = ReturnData.Descendants("Books").FirstOrDefault();
And then use it within the loop:
foreach(var b in query)
{
book.Add(new XElement("Book",
new XElement("Name", b.Name),
new XElement("Measure", b.Measure,
from m in b.NewMeasures select new XElement(m.Key, m.Value)),
new XElement("Value", b.Value)));
}

Related

How to skip a field during map stage?

I'm having list of employee objects - List
I need to convert it into list of employee transfer objects - List
Assume a field "password" exist in both the classes.
In few cases i need the password needs to be included from Employee → EmployeeDTO
In few cases i don't need the password and want to be excluded from Employee - EmployeeDTO.
Sample Code Snippet:
List<Employee> employees = employeeRepository.findAll();
// Define the target type
Type targetListType = new TypeToken<List<EmployeeDTO>>() {}.getType();
List<EmployeeDTO> employeeDTOs = modelMapper.map(employees, targetListType);
Please let me know how to skip the fields on mapping/copying.
Take a look the official user manual of Conditional Mapping.
In brief:
You would need to add a new Mapping and use a Condition. Your source and destionation would be:
Source: Employee
Destination: EmployeeDto
First create and custom your Condition. It would be something like this:
Condition<?, ?> isNotZero = new Condition<PersonDTO, Employee>() {
public boolean applies(MappingContext<PersonDTO, Employee> context) {
//Your conidition
return context.getSource().getEmployeeId() != 0;
}
};
Then add Mapping and use the condition:
modelMapper.addMappings(new PropertyMap<PersonDTO, Person>() {
protected void configure() {
when(isNotZero).map(source).setEmployee(null);
}
});
You can find this examples in the ModelMapper GitHub repository. The author has done few more and are well explained:
Link to above example
Here is how I skip fields during the mapping stage:
ModelMapper modelMapper = new ModelMapper();
modelMapper.typeMap(EmployeeDTO.class,Employee.class).addMappings(mapper -> {
mapper.skip(Employee::setPassword);
});

Error when i delete multiple rows "The object cannot be deleted because it was not found in the ObjectStateManager."

Hey Everyone i am using this code to remove multiple records in table. but it's give me an error.
"The object cannot be deleted because it was not found in the
ObjectStateManager"
I am new in EF please help me what's wrong in my code.
listOfEntities = list of record which i want to delete from table
U = it is a type entity
using (var db = new DMContext())
{
db.SaveChanges();
}
It means that the entity is not attached. You can try like this
using (var db = new DMContext())
{
db.YourTableEntity.Attach(EntityToRemove);
db.YourTableEntity.Remove(EntityToRemove);
db.SaveChanges();
}
You cannot remove the entities which are detached, so you need to first attach them and then you can remove it.
To remove multiple records
foreach (var entity in entities)
{
Set<T>().Attach(entity);
Set<T>().Remove(entity);
}
SaveChanges();

Intercepting ADD to detect if it is an ADD through a collection in Entity Framework 5

I have kinda 2 questions that can be answered separately.
Q#1
I am trying to save round trips to the database server.
Here's my algo:
Insert 2 entities (to get their IDs generated by the database)
Use the IDs returned to call a stored procedure passing it the IDs
The stored procedure takes the IDs and populates an adjacency list table which I am using to store a directed acyclic graph.
Currently I have a round-trip to the RDBMS for each parent-child relationship, plus one for the Insert of the entities.
I am known to do stuff like this:
public override int SaveChanges()
{
foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == System.Data.EntityState.Added).ToList())
{
if (entry.Entity is IRobot)
{
entry.Reference("Owner").CurrentValue = skyNet;
}
}
return base.SaveChanges();
}
So I was wondering if there was a way that I can detect an EntityState.Added for an "ADD" that was done similar to the following code:
var robot = new Robot();
skyNet.Robots.Add(robot);
db.Add(skyNet);
db.SaveChanges();
So that I can do something like this: (Note that this is psuedocode)
public override int SaveChanges()
{
foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == EntityState.**AddedToCollection**).ToList())
{
db.Relate(parent: skyNet, child: entry.Entity);
}
return base.SaveChanges();
}
Q#2
Is there anyway to call a stored procedure as part of the same "trip" to the database after calling a SaveChanges()?
Question 1
You can detect the state of an entity by
db.Entry(robot).State
After the line
skyNet.Robots.Add(robot);
the EntityState of robot will be Added. However, in your pseudocode it is not clear where the skyNet variable comes from. If you add the skyNet as you do in your code snippet you could do:
foreach( var skyNet in ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added)
.Select (e => e.Entity)
.OfType<SkyNet>())
{
foreach(var robot in skyNet.Robots
.Where(r => db.Entry(r).State == EntityState.Added))
{
db.Relate(parent: skyNet, child: robot);
}
}
Question 2
You can't call a stored procedure in one roundtrip, that would require something like NHibernate's multi query. But, you can wrap SaveChanges and a stored procedure call in one transaction (which I think is what you mean) by using TransactionScope:
using (TransactionScope scope = new TransactionScope())
{
// stored procedure call here.
db.SaveChanges();
scope.Complete();
}

Retrieve related entities of each, using RetrieveMultipleRequest

I'm trying to retrieve a list of entities from CRM, but I'd like to get each one with the related entities. So far, I've the following code:
FilterExpression filterExpression = new FilterExpression();
ConditionExpression condition = new ConditionExpression(Constants.ModifiedOnAttribute, ConditionOperator.GreaterEqual, lastSync);
filterExpression.AddCondition(condition);
QueryExpression query = new QueryExpression()
{
EntityName = entityName,
ColumnSet = new ColumnSet(attributesMetadata.Select(att => att.Name).ToArray<string>()),
Criteria = filterExpression,
Distinct = false,
NoLock = true
};
RetrieveMultipleRequest multipleRequest = new RetrieveMultipleRequest();
multipleRequest.Query = queryExpression;
RetrieveMultipleResponse response = (RetrieveMultipleResponse)proxy.Execute(multipleRequest);
In the variable response, I can see the EntityCollection attribute, but inside, Related entities always come empty.
I'd like to know if it is possible to retrieve the set of a given entities, with the related entities, using RetrieveMultipleRequest, rather than go one by one using RetrieveRequest.
One approach to retreive related entities data - adding LinkEntities to your query. Example below will make you an idea how to make this:
LinkEntity linkEntity = new LinkEntity("email", "new_emails", "activityid", "new_relatedemail", JoinOperator.Inner);
linkEntity.Columns.AddColumn("versionnumber");
linkEntity.Columns.AddColumn("new_emailsid");
linkEntity.EntityAlias = "related";
query = new QueryExpression("email");
query.ColumnSet.AddColumn("activityid");
query.ColumnSet.AddColumn("versionnumber");
query.Criteria.AddCondition("modifiedon", ConditionOperator.NotNull);
query.LinkEntities.Add(linkEntity);
And then you can access attributes from related entities using EntityAlias you specified above:
foreach (Entity entity in entities.Entities)
{
if ((long)(entity["related.versionnumber"] as AliasedValue).Value > 0)
{
stop = false;
}
}
The RetrieveMultipleRequest is for returning multiple instances of a particular type of entity. I have spent a year using the CRM SDK from C# and I have found no way of populating those related entity collections in a single query. This basically leaves you with two options:
Use the AliasedValue as SergeyS recommends. Remember when querying 1:Many relationships, be aware that you could be returning multiple results for the same parent entity. This is what I use most of the time.
Perform a second query for each relationship you want access to. You'll probably get better performance if you can use an IN statement in your second query, based on the results of the first, rather than performing a separate query for each result of the first.
Below is some pseudo code to show the difference.
var contacts = GetContacts();
// One Request to get the cars for the contacts
var cars = GetCarsWhereContactIdIn(contacts.Select( c => c.new_ContactId));
foreach(var c in contacts){
c.new_Cars.AddRange(cars.where(car => car.new_contactId = c.ContactId));
}
// Verses
var contacts = GetContacts();
foreach(var c in contacts){
// One Request for each contact
c.new_Cars.AddRange(GetCarsForContact(c.ContactId));
}

Parallel foreach ConcurrentDictionary<string, string> add

I have entries like in a phone book: name + address.
The source is on a web site, the count is over 1K records.
Question is:
How do i use/implement ConcurrentDictionary with ParallelForeach?
I might as well ask will it better perform:
ConcurrentDictionary & ParallelForeach
vs
Dictionary & foreach
As the name is not allowed to have duplicates being the key, and i think i understood correctly that ConcurrentDictionary has its own built-in function to add(TryAdd) only if key does not exists.
so the issue of not allowing adding duplicated keys already taken cared of, so from that point i could clearly see the balance is turning towards ConcurrentDictionary rather than standard-sequential Dictionary
So how do I add name & address from any given data source and load it via Parallelforeach into a ConcurrentDictionary
the count is over 1K records.
How much over 1K? Because 1K records would be added in the blink of an eye, without any need for parallelization.
Additionally, if you're fetching the data over the network, that cost will vastly dwarf the cost of adding to a dictionary. So unless you can parallelize fetching the data, there's going to be no point in making the code more complicated to add the data to the dictionary in parallel.
This is quiet an old question, but this might help someone:
If you are trying to chunk through the ConcurrentDictionary and do some processing:
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace ConcurrenyTests
{
public class ConcurrentExample
{
ConcurrentExample()
{
ConcurrentDictionary<string, string> ConcurrentPairs = new ConcurrentDictionary<string, string>();
Parallel.ForEach(ConcurrentPairs, (KeyValuePair<string, string> pair) =>
{
// Do Stuff with
string key = pair.Key;
string value = pair.Value;
});
}
}
}
I don't think you would be able to use Parallel.ForEach to be able to insert into a new dictionary unless you already had an object of same length that you were iterating over. i.e. an list with the URL's of text documents you were wanting to download and insert into the dictionary. If that were the case, then you could use something along the lines of:
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace ConcurrenyTests
{
public class ConcurrentExample
{
ConcurrentExample()
{
ConcurrentDictionary<string, string> ConcurrentPairs = new ConcurrentDictionary<string, string>();
ConcurrentBag<string> WebAddresses = new ConcurrentBag<string>();
Parallel.ForEach(WebAddresses, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (string webAddress) =>
{
// Fetch from webaddress
string webText;
// Try Add
ConcurrentPairs.TryAdd(webAddress, webText);
// GetOrUpdate
ConcurrentPairs.AddOrUpdate(webAddress, webText, (string key, string oldValue) => webText);
});
}
}
}
If accessing from a webserver, you may want to increase or decrease the MaxDefreeOfParallelism so that your bandwidth is not choked.
Parallel.ForEach: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.foreach?view=netcore-2.2
ParallelOptions: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.paralleloptions?view=netcore-2.2

Resources