The following code creates the correct number of files, but every file contains the contents of the first list. Can anyone spot what I've done wrong please?
private IList<List<string>> GetLists()
{
// Code omitted for brevity...
}
private void DoSomethingInParallel()
{
var lists = GetLists();
var tasks = new List<Task>();
var factory = new TaskFactory();
foreach (var list in lists)
{
tasks.Add(factory.StartNew(() =>
{
WriteListToLogFile(list);
}));
}
Task.WaitAll(tasks.ToArray());
}
The reason why is down to the way C# evaluates anonymous methods, they're not true closures. It really has nothing to do with the TPL. The following code prints out all d's. This is not what yoy would expect
List<Task> tasks = new List<Task>();
List<string> lists = new List<string>();
lists.AddRange(new string[] { "a", "b", "c", "d" });
foreach (var list in lists)
{
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(list);
}));
}
The reason is because the value of list when the anonymous method was created is not the one that gets evaluated in the method body. The value of list at the time the method was executed is used. You can force a fix for this by doing the following:
List<Task> tasks = new List<Task>();
List<string> lists = new List<string>();
lists.AddRange(new string[] { "a", "b", "c", "d" });
foreach (var list in lists)
{
var localList = list;
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine(localList);
}));
}
You don't have to pass in the list value to the anonymous method explicitly.
This blog post goes into this in much more detail:
Link
Apologies for not replying to this earlier. I found a solution - although I don't understand why it works...
Originally, I had this ...
foreach (var list in lists)
{
tasks.Add(factory.StartNew(() =>
{
WriteListToLogFile(list);
}));
}
Changing the sequential foreach to a parallel foreach fixes the problem...
Parallel.ForEach<string>(lists, list =>
tasks.Add(factory.StartNew(() =>
{
WriteListToLogFile(list);
}));
);
I am not sure why you have a list for "tasks", you are only ever using one of them.
edit:
factory.StartNew Creates and starts a System.Threading.Tasks.Task!!
Thinking out loud:
so there is a separate task for each of the List<String> in its list which calls WriteListToLogFile?
I think you will need to use
ThreadPool.QueueUserWorkItem
in your code after task.Add
look at this example (see the accepted answer post) link
Ran into this same problem myself. I'm still not sure why it happens, but I was able to get it to work properly by passing in a state object
foreach (var list in lists)
{
tasks.Add(factory.StartNew((o) =>
{
var l = o as List<string>;
WriteListToLogFile(l);
}, list));
}
Related
I have a database with a hierarchy of categories. Each category has a parentcategoryid. I call the following function to load the top level categories and then it recursively calls itself to load all the children.
However, I get the following error:
SqlException: New transaction is not allowed because there are other
threads running in the session.
public async Task LoadCategoriesAsync()
{
await LoadCategoriesByParentId(null);
}
private async Task LoadCategoriesByParentId(int? sourceParentId, int? parentId)
{
var sourceCategories = _dbContext.SourceCategory.Where(c => c.ParentCategoryId == sourceParentId);
foreach (var sourceCategory in sourceCategories)
{
var newCategory = new Category()
{
Name = sourceCategory.Name,
Description = sourceCategory.Description,
ParentCategoryId = parentId
};
_dbContext.Category.Add(newCategory);
await _dbContext.SaveChangesAsync();
//category.EntityId = newCategory.Id;
//_dbContext.SourceCategory.Update(category);
//await _dbContext.SaveChangesAsync();
await LoadCategoriesByParentId(sourceCategory.CategoryId, newCategory.Id);
}
}
Your Where() statement doesn't retrieve the data; just "opens the cursor" (in old-speak). So, you can't do SaveChange(). The simplest solution is to convert IEnumerable to List or Array:
var rootCategories = _dbContext.SourceCategory.Where(c => c.ParentCategoryId == parentId).ToList();
But I would strongly recommend you google the error and understand why it is happening. To do this recursively is begging for trouble
Seems that the SaveChanges() only saves the last object added into the table:
static void Main(string[] args)
{
Category c = new Category();
using (GenericDBEntities db = new GenericDBEntities())
{
foreach (Match i in db.Matches)
{
if (!db.Categories.Any())
{
c.CategoryInternalId = i.CategoryId;
c.CategoryName = i.CategoryName;
c.SportId = i.SportId;
db.Categories.Add(c);
}
else
{
foreach (Category a in db.Categories)
{
if (i.CategoryId != a.CategoryInternalId)
{
c.CategoryInternalId = i.CategoryId;
c.CategoryName = i.CategoryName;
c.SportId = i.SportId;
db.Categories.Add(c);
}
else
{
return;
}
}
}
}
db.SaveChanges();
I have tried it in a few different ways which all have the same or less result, the for loop saves them all, no matter if condition is met or not. Why is it only saving the last object of the Match table? What am I missing?
Clarification: The task is to go through Match table, which has duplicate CategoryIDs and to, if it is not already in the Category table, add it, so it won't store duplicates again, the problem is Category table is initially empty, hence the newbie logic, still learnin'!
You need to create the Category object for each inserted category, otherwise you have just one category object which you are editing all the time and hence just this one (the last edit) will be saved to the DB.
If you want to add all new categories from Matches based on CategoryId you can use something like this:
using (GenericDBEntities db = new GenericDBEntities())
{
var newCategories = db.Matches
.Where(m => !db.Categories
.Select(c => c.CategoryInternalId)
.Distinct().Contains(m.CategoryId))
.Select(m => new { m.CategoryId, m.CategoryName, m.SportId })
.GroupBy(m => m.otherid)
.Select(g => g.FirstOrDefault())
.ToList();
foreach (var i in newCategories)
{
var c = new Category()
{
CategoryInternalId = i.CategoryId,
CategoryName = i.CategoryName,
SportId = i.SportId
};
db.Categories.Add(c);
}
db.SaveChanges();
}
Now you'll get all the new categories from the Matches table in one go. This is a first draft, meaning that the performance can be further tuned if needed.
With libgit2sharp I would like to do the following:
foreach( Commit commit in repo.Commits )
{
// How to implement assignedTags?
foreach( Tag tag in commit.assignedTags ) {}
}
I want to get all tags assigned to the current commit. Whats the best way to do that? Iterate through all Tags and see if tag.Target.Sha == commit.Sha? Thats not very performant. Is there another way?
So I want to get all tags assigned to the current commit. Whats the best way to do that? Iterate through all Tags and see if tag.Target.Sha == commit.Sha? Thats not very performant. Is there another way?
There are two things to take into account when it comes to Tags.
A Tag can point to something else than a Commit (A Tree or a Blob, for instance)
A Tag can point to another Tag (chained annotated tags)
The code below should fit your need by taking these points above into account.
Note: repo.Commits will only enumerate the commits reachable from the current branch (HEAD). The code below
extends this to easily browse all the reachable commits.
...
using (var repo = new Repository("Path/to/your/repo"))
{
// Build up a cached dictionary of all the tags that point to a commit
var dic = TagsPerPeeledCommitId(repo);
// Let's enumerate all the reachable commits (similarly to `git log --all`)
foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter {Since = repo.Refs}))
{
foreach (var tags in AssignedTags(commit, dic))
{
Console.WriteLine("Tag {0} points at {1}", tags.Name, commit.Id);
}
}
}
....
private static IEnumerable<Tag> AssignedTags(Commit commit, Dictionary<ObjectId, List<Tag>> tags)
{
if (!tags.ContainsKey(commit.Id))
{
return Enumerable.Empty<Tag>();
}
return tags[commit.Id];
}
private static Dictionary<ObjectId, List<Tag>> TagsPerPeeledCommitId(Repository repo)
{
var tagsPerPeeledCommitId = new Dictionary<ObjectId, List<Tag>>();
foreach (Tag tag in repo.Tags)
{
GitObject peeledTarget = tag.PeeledTarget;
if (!(peeledTarget is Commit))
{
// We're not interested by Tags pointing at Blobs or Trees
continue;
}
ObjectId commitId = peeledTarget.Id;
if (!tagsPerPeeledCommitId.ContainsKey(commitId))
{
// A Commit may be pointed at by more than one Tag
tagsPerPeeledCommitId.Add(commitId, new List<Tag>());
}
tagsPerPeeledCommitId[commitId].Add(tag);
}
return tagsPerPeeledCommitId;
}
Here is another version of nulltoken's answer but with using ILookupclass instead of dictionary. A bit nicer IMO:
private static ILookup<ObjectId, Tag> CreateCommitIdToTagLookup(Repository repo)
{
var commitIdToTagLookup =
repo.Tags
.Select(tag => new { Commit = tag.PeeledTarget as Commit, Tag = tag })
.Where(x => x.Commit != null)
.ToLookup(x => x.Commit.Id, x => x.Tag);
return commitIdToTagLookup;
}
and simple usage example:
using (var repo = new Repository("Path/to/your/repo"))
{
var commitIdToTagLookup = CreateCommitIdToTagLookup(repo);
foreach (var commit in repo.Commits)
{
foreach (var tag in commitIdToTagLookup[commit.Id])
{
Console.WriteLine($"Tag {tag.FriendlyName} points at {commit.Id}");
}
}
}
I have a entity record which is shared with or more users. I would like to unshare this record when Deactivate it. I want to do that in Plugin. But I can't understand how to get all users from sharing list who have access to this record. How to do that?
Here is my code snippet:
protected void ExecutePostPersonSetStateDynamicEntity(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var context = localContext.PluginExecutionContext;
var targetEntity = (Entity)context.InputParameters["EntityMoniker"];
var state = (OptionSetValue)context.InputParameters["State"];
var columns = new ColumnSet(new[] { "statecode" });
var retrivedEntity = localContext.OrganizationService.Retrieve(targetEntity.LogicalName, targetEntity.Id, columns);
if (state.Value == 1)
{
RevokeAccessRequest revokeRequest = new RevokeAccessRequest()
{
Target = new EntityReference(personEntity.LogicalName, personEntity.Id),
Revokee = new EntityReference(neededEntity.LogicalName, needed.Id)
};
// Execute the request.
}
}
As you can see, I need an entity "neededEntity", I don't know how to get it from "targetEntity" or "retrievedEntity".
You need to use a RetrieveSharedPrincipalsAndAccessRequest
http://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx
You can start from the included example, basically inside the foreach you call your RevokeAcessRequest
In Global.asax, I want to add a number of display modes dynamically, based on a string array I have, thus:
foreach (string displayModeId in myDisplayModeIds)
{
modes.Insert(0, new DefaultDisplayMode(displayModeId)
{
ContextCondition = context =>
context.Request["DisplayMode"] == displayModeId
}
);
}
Of course this doesn't work, because displayModeId needs to be a constant within the scope of the ContextCondition.
Any help appreciated.
You could capture it in a closure so that it doesn't run away from you in the loop:
foreach (string displayModeId in myDisplayModeIds)
{
string dmId = displayModeId;
modes.Insert(0, new DefaultDisplayMode(displayModeId)
{
ContextCondition = context => context.Request["DisplayMode"] == dmId
});
}