I am forming an object based on list coming from input along with the string like as below.
public static LibrarySourceTableInput CreateLibrarySourceTableInput<T>(List<T> libraries, string mechanicalLibraryName)
where T : ISourceOfData
{
return new LibrarySourceTableInput()
{
LibrarySourceRowInputs = libraries?.Select(l => new LibrarySourceRowInput()
{
LibrarySourceId = l.Id,
SourceOfDataId = l.SourceOfData.Id
}).ToList() ?? new(),
MappedLibrarySource = mechanicalLibraryName
};
}
I am facing different problem here, I have libraries count coming as 1 but internal object is null for example in the below image libraries count as 1 and it is null,
and in this case I am getting a null reference exception with the above code, could any one please help on this how to avoid that null exception. Many thanks in advance.
You could do a where query before the select.
LibrarySourceRowInputs = libraries?.Where(l => l != null)
.Select(l => l => new LibrarySourceRowInput()
{
LibrarySourceId = l.Id,
SourceOfDataId = l.SourceOfData.Id
}).ToList() ?? new();
Related
I have the below code . Here i want to find out servicelevelid in lstServiceLevels List which is an array of objects of ServiceLevelDetails where ServiceLevelName is "Basic"
Could anyone please help me to get it ?
public class ServiceLevelDetails
{
public int servicelevelid;
public string ServiceLevelName;
}
class Program
{
static void Main(string[] args)
{
IList<ServiceLevelDetails> lstServiceLevels = new List<ServiceLevelDetails>();
ServiceLevelDetails one = new ServiceLevelDetails();
one.servicelevelid=1;
one.ServiceLevelName="Basic";
ServiceLevelDetails Two = new ServiceLevelDetails();
Two.servicelevelid = 2;
Two.ServiceLevelName = "Enhanced";
lstServiceLevels.Add(one);
lstServiceLevels.Add(Two);
var test = from LevelName in lstServiceLevels
let LevelName= obj as ServiceLevelDetails
where LevelName.ServiceLevelName == "Basic"
select LevelName;
//getting error in the above code .
}
}
There is nothing in your scope called obj, so it's not clear why this is in your query.
In LINQ query syntax, it sounds like you want this:
from serviceLevel in lstServiceLevels
where serviceLevel.ServiceLevelName == "Basic"
select serviceLevel;
Or in LINQ method syntax:
lstServiceLevels.Where(x => x.ServiceLevelName == "Basic");
If, as you suggest in the comments, you want the id for a specific name:
var id = lstServiceLevels
.Where(x => x.ServiceLevelName == "Basic")
.Select(x => x.servicelevelid)
.Single();
here is an alternative with which you don't run into exceptions
when the element cannot be found.
look for the first occurrence of this element:
// FirstOrDefault will return null if nothing was found
// but it also will return only the first element!
var id_test = lstServiceLevels.FirstOrDefault(x => x.ServiceLevelName == "Basic");
// then you can check for it and take the ID if it was found
// or else assign some other value
int id = id_test != null ? id_test.servicelevelid : 0;
it's of course a matter of taste either to use try/catch or null testing :)
I'm trying to figure out how to get the depth of a relationship of an entity that can relate to itself. That is There is a base comment item, which can have one or more reply comments linked to it.
Now for each one of these replied comments I want to know how deep they are from the top node.
ie, I want to know the Depth in the comments in the image below:
This is the code as of now, and the variable ResponseTo is the relationship that this comment is a response to, if is is not a response the value is null
var comments = db.Comments
.Where(c => c.Post.ID == id && c.Status == Helpers.StatusCode.Visible)
.Select(x => new CommentTemp()
{
Id = x.ID,
Text = x.Text,
Avatar = "-1",
Username = (x.User != null ? x.User.UserName : "Anonymous"),
UserID = (x.User != null ? (int?) x.User.Id : null),
ResponseTo = (x.ResponseTo == null ? null : (int?) x.ResponseTo.ID),
CommentDepth = ??? // <--- how do i select the depth of the response to relations?
Created = x.Created
})
.ToList();
Only option I can think of right now is saving it as the comment is created, but if possible I would like to get it on the fly.
Well, it indeed sounds like you want to hold such information in the database, unless there's really good reason not to. Either way, Linq is not really recursive friendly.
You can get the depth by creating dictionary & tracking it back recursively.
int GetDepth(Comment comment,
IDictionary<int, Comment> comments, /*key=commentId, val=Comment*/
IDictionary<int, int> depthMemoization, /* key=commentId, val=depth*/
int currentDepth = 0)
{
if(depthMemoization.ContainsKey(comment.Id))
return depthMemoization[comment.Id];
if(comment.ParentId==null)
return currentDepth;
var parentComment = comments[comment.ParentId.Value];
int calculatedDepth = GetDepth(parentComment, comments,
depthMemoization,
++currentDepth);
depthMemoization[comment.Id] = calculatedDepth ;
return depth;
}
I want to return the category Name or just null within the projection below, but I get a null reference exception, which makes sense if result.CategoryId is null.
return results.Select(i =>
new Model
{
Score = i.Score
,Date = i.InstanceResult.TestDate
,Category = categories.Where(c=>c.Id.Equals(i.result.CategoryId)).SingleOrDefault().Name
});
You need to check if there's a category with that Id then decide what value to assign.
return results.Select(i =>
new Model
{
Score = i.Score
,Date = i.InstanceResult.TestDate
,Category = categories.Any(c => c.Id.Equals(i.result.CategoryId)) ?
categories.First(c => c.Id.Equals(i.result.CategoryId)).Name :
null
});
You could tidy this up with an extension method like so
...
Category = categories.GetNameFromId(i.result.CategoryId)
...
public static string GetNameFromId(this IEnumerable<Category> categories, string id)
{
return categories.Any(c => c.Id.Equals(id)) ?
categories.First(c => c.Id.Equals(id)).Name :
null
}
You can use FirstOrDefault like this but you need to execute same query twice, if you want to do that in one statement:
Category = categories
.FirstOrDefault(c=> c.Id.Equals(i.result.CategoryId)) != null ?
categories
.FirstOrDefault(c=> c.Id.Equals(i.result.CategoryId)).Name : null;
return results.Select(i =>
{
var singleOrDefault = categories.SingleOrDefault(c => c.Id.Equals(i.result.CategoryId));
return new Model
{
Score = i.Score,
Date = i.InstanceResult.TestDate,
Category = singleOrDefault != null ? singleOrDefault.Name : null
};
});
categories.Where(c=>c.Id.Equals(i.result.CategoryId)).SingleOrDefault()
returns null if nothing has been found. If you then try to access ".Name" it will throw an exception like you have got.
Try to make it that way:
Category singleCategory = categories.Where(c=>c.Id == i.result.CategoryId).SingleOrDefault();
if (singleCategory != null)
{
// Do something with the Properties
}
I know this question was asked too many times here but I still cannot figure out what is wrong with my code.
I have a class implementing singleton. The class uses a web service proxy to access data. The data is cached and 2 subsequent calls should result in a single call to the service. It actually works, I can see it when stepping through, but the test fails.
[Test]
public void Test1()
{
Mock<IAtomService> atomService = new Mock<IAtomService>();
atomService.Setup(x => x.Get(It.IsAny<List<Identifier>>(), It.IsAny<AtomReturnFormat>()))
.Returns<List<Identifier>, AtomReturnFormat>(
(list, format) => new AtomList { Atoms = new AtomCollection(list.Select(ident => new Atom { ID = Guid.Parse(ident.ID) })) });
AtomCache.Instance.AtomService = atomService.Object;
Guid id = Guid.NewGuid();
List<string> ids = new List<string> { id.ToString() };
AtomCache cache1 = AtomCache.Instance;
cache1.Get(ids);
AtomCache cache2 = AtomCache.Instance;
cache2.Get(ids);
AtomService.Verify(x => x.Get(It.IsAny<List<Identifier>>(), It.IsAny<AtomReturnFormat>()), Times.Once());
}
The error is
Expected invocation on the mock once, but was 0 times: x => x.Get(It.IsAny<List`1>(), It.IsAny<AtomReturnFormat>())
Configured setups:
x => x.Get(It.IsAny<List`1>(), It.IsAny<AtomReturnFormat>()), Times.Never
No invocations performed.
Any help is very appreciated
Update
public List<Atom> Get(List<string> atomIds)
{
if (atomIds == null)
throw new ArgumentNullException("atomIds");
Dictionary<string, Atom> cachedAtoms = Cache.Get(atomIds.Where(id => !string.IsNullOrEmpty(id)).Distinct().ToList());
List<Atom> atoms = new List<Atom>();
if (cachedAtoms != null)
{
List<string> missingAtomIds = atomIds.Except(cachedAtoms.Keys).ToList();
atoms.AddRange(getMissingAtoms(missingAtomIds));
atoms.AddRange(cachedAtoms.Where(kv => kv.Value != null).Select(kv => kv.Value));
}
return atoms;
}
private IEnumerable<Atom> getMissingAtoms(List<string> atomIds)
{
if (atomIds == null)
throw new ArgumentNullException("atomIds");
List<Atom> atoms = new List<Atom>();
if (atomIds.Count > 0)
{
List<Atom> list = retrieveAtoms(atomIds);
Cache.Add(list);
atoms.AddRange(list);
}
return atoms;
}
private List<Atom> retrieveAtoms(List<string> atomIDs)
{
if (atomIDs == null)
throw new ArgumentNullException("atomIDs");
if (AtomService == null)
throw new ApplicationException("AtomCache: Atom Service proxy is not initialized.");
Guid temp;
List<Identifier> idList = atomIDs.Where(id => !string.IsNullOrWhiteSpace(id) && Guid.TryParse(id, out temp))
.Select(id => new Identifier {ID = id, Type = IdentifierTypeEnum.AtomPrimary})
.ToList();
List<Atom> atoms = atomIDs.Count == 0
? new List<Atom>()
: ((AtomList) AtomService.Get(idList, AtomReturnFormat.Complete)).Atoms.ToList();
return atoms;
}
Unless I missed something changed in your update, I think you're this is the problem.
In your setup, you tell the mock what to return if a list of Identifiers are passed to it:
atomService.Setup(x => x.Get(It.IsAny<List<Identifier>>(), %<--snip--
However when you call, you're passing a list of strings:
List<string> ids = new List<string> { id.ToString() };
AtomCache cache1 = AtomCache.Instance;
cache1.Get(ids);
And I don't see anywhere that this list of strings is converted to a list of identifiers, so the mock never meets your setup condition, which is: when asked for any list of Identifiers, and therefore it properly reports it was asked 0 times.
I figured out what was the problem. It was a different instance of the mock that I called Verify on. when I copied the code in here, I simplified the code and it fixed the error :)
thank you
Anyone know how I can set a default value for an average? I have a line like this...
dbPlugins = (from p in dbPlugins
select new { Plugin = p, AvgScore = p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) })
.OrderByDescending(x => x.AvgScore)
.Select(x => x.Plugin).ToList();
which throws an error becase I have no ratings yet. If I have none I want the average to default to 0. I was thinking this should be an extension method where I could specify what the default value should be.
There is: DefaultIfEmpty.
I 'm not sure about what your DbVersions and DbRatings are and which collection exactly has zero items, but this is the idea:
var emptyCollection = new List<int>();
var average = emptyCollection.DefaultIfEmpty(0).Average();
Update: (repeating what's said in the comments below to increase visibility)
If you find yourself needing to use DefaultIfEmpty on a collection of class type, remember that you can change the LINQ query to project before aggregating. For example:
class Item
{
public int Value { get; set; }
}
var list = new List<Item>();
var avg = list.Average(item => item.Value);
If you don't want to/can not construct a default Item with Value equal to 0, you can project to a collection of ints first and then supply a default:
var avg = list.Select(item => item.Value).DefaultIfEmpty(0).Average();
My advice would to create a reusable solution instead of a solution for this problem only.
Make an extension method AverageOrDefault, similar to FirstOrDefault. See extension methods demystified
public static class MyEnumerableExtensions
{
public static double AverageOrDefault(this IEnumerable<int> source)
{
// TODO: decide what to do if source equals null: exception or return default?
if (source.Any())
return source.Average();
else
return default(int);
}
}
There are 9 overloads of Enumerable.Average, so you'll need to create an AverageOrDefault for double, int?, decimal, etc. They all look similar.
Usage:
// Get the average order total or default per customer
var averageOrderTotalPerCustomer = myDbContext.Customers
.GroupJoin(myDbContext.Orders,
customer => customer.Id,
order => order.CustomerId,
(customer, ordersOfThisCustomer) => new
{
Id = customer.Id,
Name = customer.Name,
AverageOrder = ordersOfThisCustomer.AverageOrDefault(),
});
I don't think there's a way to select default, but how about this query
dbPlugins = (from p in dbPlugins
select new {
Plugin = p, AvgScore =
p.DbVersions.Any(x => x.DbRatings) ?
p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) : 0 })
.OrderByDescending(x => x.AvgScore)
.Select(x => x.Plugin).ToList();
Essentially the same as yours, but we first ask if there are any ratings before averaging them. If not, we return 0.