Count the number of indirectly used assemblies in NDepend - ndepend

I'm trying to count the indirect assembly references. The following does not work because IsIndirectlyUsing wants a constant string: "Only constant literal string are accepted as input for IsIndirectlyUsing(string)"
Is there a method to get the indirect assemblies used?
from a in Assemblies
let indirectlyUsed =
from dep in Assemblies
let depName = a.FullName
where a.IsIndirectlyUsing(depName)
select dep
where a.PDBFound orderby a.AssembliesUsed.Count() descending
select new { a, a.AssembliesUsed, indirectlyUsed, a.NbLinesOfCode, a.NbILInstructions }```

The NDepend.API method FillIterative() is here to help:
from a in Assemblies
let indirectlyUsed = a.AssembliesUsed.FillIterative(
asms => asms.SelectMany(a1 => a1.AssembliesUsed)).DefinitionDomain
where a.PDBFound orderby indirectlyUsed .Count() descending
select new { a, a.AssembliesUsed, indirectlyUsed, a.NbLinesOfCode, a.NbILInstructions }

Related

How to fix FirstOrDefault returning Null in Linq

My Linq Query keeps returning the null error on FirstOrDefault
The cast to value type 'System.Int32' failed because the materialized value is null
because it can't find any records to match on the ClinicalAssetID form the ClinicalReading Table, fair enough!
But I want the fields in my details page just to appear blank if the table does not have matching entry.
But how can I handle the null issue when using the order by function ?
Current Code:
var ClinicalASSPATINCVM = (from s in db.ClinicalAssets
join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
from subASSPAT in AP.DefaultIfEmpty()
join ci in db.ClinicalINSs on s.ClinicalAssetID equals ci.ClinicalAssetID into AI
from subASSINC in AI.DefaultIfEmpty()
join co in db.ClinicalReadings on s.ClinicalAssetID equals co.ClinicalAssetID into AR
let subASSRED = AR.OrderByDescending(subASSRED => subASSRED.MeterReadingDone).FirstOrDefault()
select new ClinicalASSPATINCVM
{
ClinicalAssetID = s.ClinicalAssetID,
AssetTypeName = s.AssetTypeName,
ProductName = s.ProductName,
ModelName = s.ModelName,
SupplierName = s.SupplierName,
ManufacturerName = s.ManufacturerName,
SerialNo = s.SerialNo,
PurchaseDate = s.PurchaseDate,
PoNo = s.PoNo,
Costing = s.Costing,
TeamName = s.TeamName,
StaffName = s.StaffName,
WarrantyEndDate = subASSPAT.WarrantyEndDate,
InspectionDate = subASSPAT.InspectionDate,
InspectionOutcomeResult = subASSPAT.InspectionOutcomeResult,
InspectionDocumnets = subASSPAT.InspectionDocumnets,
LastTypeofInspection = subASSINC.LastTypeofInspection,
NextInspectionDate = subASSINC.NextInspectionDate,
NextInspectionType = subASSINC.NextInspectionType,
MeterReadingDone = subASSRED.MeterReadingDone,
MeterReadingDue = subASSRED.MeterReadingDue,
MeterReading = subASSRED.MeterReading,
MeterUnitsUsed = subASSRED.MeterUnitsUsed,
FilterReplaced = subASSRED.FilterReplaced
}).FirstOrDefault(x => x.ClinicalAssetID == id);
Tried this but doesn't work
.DefaultIfEmpty(new ClinicalASSPATINCVM())
.FirstOrDefault()
Error was:
CS1929 'IOrderedEnumerable<ClinicalReading>' does not contain a definition for 'DefaultIfEmpty' and the best extension method overload 'Queryable.DefaultIfEmpty<ClinicalASSPATINCVM>(IQueryable<ClinicalASSPATINCVM>, ClinicalASSPATINCVM)' requires a receiver of type 'IQueryable<ClinicalASSPATINCVM>'
Feel a little closer with this but still errors
let subASSRED = AR.OrderByDescending(subASSRED => (subASSRED.MeterReadingDone != null) ? subASSRED.MeterReadingDone : String.Empty).FirstOrDefault()
Error:
CS0173 Type of conditional expression cannot be determined because there is no implicit conversion between 'System.DateTime?' and 'string'
The original error means that some of the following properties of the ClinicalASSPATINCVM class - MeterReadingDone, MeterReadingDue, MeterReading, MeterUnitsUsed, or FilterReplaced is of type int.
Remember that subASSRED here
let subASSRED = AR.OrderByDescending(subASSRED => subASSRED.MeterReadingDone).FirstOrDefault()
might be null (no corresponding record).
Now look at this part of the projection:
MeterReadingDone = subASSRED.MeterReadingDone,
MeterReadingDue = subASSRED.MeterReadingDue,
MeterReading = subASSRED.MeterReading,
MeterUnitsUsed = subASSRED.MeterUnitsUsed,
FilterReplaced = subASSRED.FilterReplaced
If that was LINQ to Objects, all these would generate NRE (Null Reference Exception) at runtime. In LINQ to Entities this is converted and executed as SQL. SQL has no issues with expression like subASSRED.SomeProperty because SQL supports NULL naturally even if SomeProperty normally does not allow NULL. So the SQL query executes normally, but now EF must materialize the result into objects, and the C# object property is not nullable, hence the error in question.
To solve it, find the int property(es) and use the following pattern inside query:
SomeIntProperty = (int?)subASSRED.SomeIntProperty ?? 0 // or other meaningful default
or change receiving object property type to int? and leave the original query as is.
Do the same for any non nullable type property, e.g. DateTime, double, decimal, Guid etc.
You're problem is because your DefaultIfEmpty is executed AsQueryable. Perform it AsEnumerable and it will work:
// create the default element only once!
static readonly ClinicalAssPatInVcm defaultElement = new ClinicalAssPatInVcm ();
var result = <my big linq query>
.Where(x => x.ClinicalAssetID == id)
.AsEnumerable()
.DefaultIfEmpty(defaultElement)
.FirstOrDefault();
This won't lead to a performance penalty!
Database management systems are extremely optimized for selecting data. One of the slower parts of a database query is the transport of the selected data to your local process. Hence it is wise to let the DBMS do most of the selecting, and only after you know that you only have the data that you really plan to use, move the data to your local process.
In your case, you need at utmost one element from your DBMS, and if there is nothing, you want to use a default object instead.
AsQueryable will move the selected data to your local process in a smart way, probably per "page" of selected data.
The page size is a good compromise: not too small, so you don't have to ask for the next page too often; not too large, so that you don't transfer much more items than you actually use.
Besides, because of the Where statement you expect at utmost one element anyway. So that a full "page" is fetched is no problem, the page will contain only one element.
After the page is fetched, DefaultIfEmpty checks if the page is empty, and if so, returns a sequence containing the defaultElement. If not, it returns the complete page.
After the DefaultIfEmpty you only take the first element, which is what you want.

Scala: mutable.Map[Any, mutable.Map[Any, IndexedSeq[Any]] issue

I have a tiny problem when trying to put an item in my second mutable map.
My objective: gather some elements located in many different xml files, and organise them in the hierarchy they belong (the files are an unstructured mess, with categories being given in seemingly no logical order).
Those elements are: the level in hierarchy of the category (1 - x, 1 is top level) as iLevel, the category code as catCode, its name, and if need be, the name of its parents (all names located in namesCategories).
val categoryMap = mutable.Map.empty[Int, mutable.Map[String, IndexedSeq[String]]]
...
//Before: search in a first file links to other files
// for each category file found, will treat it and store it for further treatement.
matches.foreach{f =>
....
//Will search for a specific regex, and for each matches store what we are interested in
matchesCat.foreach{t =>
sCat = t.replaceFirst((system_env + """\S{4}"""), "")
//iLevel given by the number of '/' remaining in the string
iLevel = sCat.count(_ == '/')
//reset catCode and namesCategories
catCode = ""
namesCategories.clear()
//Search and extract the datas from sCat using premade regex patterns
sCat match {
case patternCatCode(codeCat) => catCode = s"$codeCat"
}
//remove the category code to prepare to extract names
sCat.replace(patternCatCode.toString(), "")
//extract names
do {
sCat match {
case patternCatNames(name) => namesCategories += s"$name"
}
sCat.replace(patternCatNames.toString(), "")
}while(sCat!="")
// create the level entry if it doesn't exist
if(!(categoryMap.contains(iLevel))) {
categoryMap.put(iLevel, mutable.Map.empty[String, IndexedSeq[String]])
}
//Try to add my cat code and the names, which must be in order for further treatment, to my map
categoryMap(iLevel).put(catCode, namesCategories.clone())
}
}
}
Problem:
Type mismatch, expected: IndexedSeq[String], actual: mutable.Builder[String, IndexedSeq[String]]
As Travis Brown kindly noted, I have an issue with a type mismatch, but I don't know how to fix that and get the general idea working.
I tried to keep the code to only what is relevant here, if more is needed I'll edit again.
Any tips?
Thanks for your help

How to access the package by name

We have the model which contains packages and sub packages.So how can we move the pointer to the specific package by the package name.So is there any way to iterate through the model and get the package by name
Use
Repositore.SQLQuery("SELECT package_id FROM t_package WHERE name=<theName>")
That will return a XML result set containing all packages with the name you are looking for. It might look like this:
<?xml version="1.0"?>
<EADATA version="1.0" exporter="Enterprise Architect">
<Dataset_0><Data><Row><package_id>1</package_id></Row><Row><package_id>2</package_id></Row><Row><package_id>3</package_id></Row></Data></Dataset_0></EADATA>
So you can either stuff that in a XML parser or use a regular expression like
/package_id>(\d+)/
to filter all the package-ids.
In turn simply use
Repository.GetPackageById(<found id>)
to access the found package(s).
As pointed out in the comment, this will work:
List<EA.Package> myPacks = new List<EA.Package>();
public void GOThroughAllPackages(EA.Package dumpPackage)
{
foreach (EA.Package packages in dumpPackage.Packages)
{
if(packages.Name.ToLower().Equals(requiredPackName))
{
myPacks.Add(packages);
break;
}
GOThroughAllPackages(packages);
}
}
Alternate solution (C#) that doesn't require parsing an xml string:
List<EA.Package> packages = new List<EA.Package>();
string searchValue = "somePackageName";
var packageElements = Repository.GetElementSet("select o.Object_ID from t_object o inner join t_package p on p.ea_guid = o.ea_guid where o.Name = '"+searchValue+"'",2);
foreach (EA.Element packageElement in packageElements)
{
packages.Add(Repository.GetPackageByGuid(packageElement.ElementGUID);)
}
It uses the Repository.GetElementSet() with parameter 2 that tells it to accept an SQL query.
Note that this solution will not return root packages as they don't have an t_object counterpart.

How do you specify multi-column OrderSpecifier for use in SpringData and QueryDsl? Is this possible

So I have the following query below:
public Iterable<Dealer> findAll(Dealer dealer) {
QDealer qdealer = QDealer.dealer;
BooleanExpression where = null;
if(dealer.getId() != null && dealer.getId() != 0) {
buildPredicate(qdealer.id.goe(dealer.getId()));
}
OrderSpecifier<String> sortOrder = QDealer.dealer.dealerCode.desc();
Iterable<Dealer> results = dlrRpstry.findAll(where, sortOrder);
return results;
}
The query above works fine. However, I would like to sort the results by dealerType first, then by dealerCode somewhat like "order by dealerType asc, dealerCode desc". How do I instantiate the OrderSpecifier so that the results will be sorted by dealerType then by dealer code.
The DealerRepository dlrRpstry extends JpaRepository, QueryDslPredicateExecutor
I am using spring-data-jpa-1.1.0, spring-data-commons-dist-1.3.2 and querydsl-jpa-2.9.0.
If OrderSpecifier can not be configured to a multi-column sort order what would be the alternative solution that will satisfy my requirement of sorting the results "by dealerType asc, dealerCode desc".
Any help would be greatly appreciated. Thanks in advance.
Nick
I do not have JPA install setup, but I believe reading the QueryDslJpaRepository documentation, you can simply do this:
OrderSpecifier<String> sortOrder1 = QDealer.dealer.dealerType.asc();
OrderSpecifier<String> sortOrder2 = QDealer.dealer.dealerCode.desc();
Iterable<Dealer> results = dlrRpstry.findAll(where, sortOrder1, sortOrder2);
Let us know if it works. Here is a link to a stackoverflow question/answer that explains the ... parameter syntax on the findAll() method:
https://stackoverflow.com/a/12994104/2879838
This means you can have as many OrderSpecifiers as you want as optional parameters to the function.
If you don't want to create variable for each specifier, it can be done this way:
OrderSpecifier<?>[] sortOrder = new OrderSpecifier[] {
QDealer.dealer.dealerType.asc(),
QDealer.dealer.dealerCode.desc()
};
Iterable<Dealer> results = dlrRpstry.findAll(where, sortOrder);

Linq to Entities does not recognize the method System.DateTime.. and cannot translate this into a store expression

I have a problem that has taken me weeks to resolve and I have not been able to.
I have a class where I have two methods. The following is supposed to take the latest date from database. That date represents the latest payment that a customer has done to "something":
public DateTime getLatestPaymentDate(int? idCustomer)
{
DateTime lastDate;
lastDate = (from fp in ge.Payments
from cst in ge.Customers
from brs in ge.Records.AsEnumerable()
where (cst.idCustomer == brs.idCustomer && brs.idHardBox == fp.idHardbox
&& cst.idCustomer == idCustomer)
select fp.datePayment).AsEnumerable().Max();
return lastDate;
}//getLatestPaymentDate
And here I have the other method, which is supposed to call the previous one to complete a Linq query and pass it to a Crystal Report:
//Linq query to retrieve all those customers'data who have not paid their safebox(es) annuity in the last year.
public List<ReportObject> GetPendingPayers()
{
List<ReportObject> defaulterCustomers;
defaulterCustomers = (from c in ge.Customer
from br in ge.Records
from p in ge.Payments
where (c.idCustomer == br.idCustomer
&& br.idHardBox == p.idHardBox)
select new ReportObject
{
CustomerId = c.idCustomer,
CustomerName = c.nameCustomer,
HardBoxDateRecord = br.idHardRecord,
PaymentDate = getLatestPaymentDate(c.idCustomer),
}).Distinct().ToList();
}//GetPendingPayers
No compile error is thrown here, but when I run the application and the second method tries to call the first one in the field PaymentDate the error mentioned in the header occurs:
Linq to Entities does not recognize the method System.DateTime.. and cannot translate this into a store expression
Please anybody with an useful input that put me off from this messy error? Any help will be appreciated !
Thanks a lot !
Have a look at these other questions :
LINQ to Entities does not recognize the method
LINQ to Entities does not recognize the method 'System.DateTime Parse(System.String)' method
Basically, you cannot use a value on the C# side and translate it into SQL. The first question offers a more thorough explanation ; the second offers a simple solution to your problem.
EDIT :
Simply put : the EF is asking the SQL server to perform the getLatestPaymentDate method, which it has no clue about. You need to execute it on the program side.
Simply perform your query first, put the results into a list and then do your Select on the in-memory list :
List<ReportObject> defaulterCustomers;
var queryResult = (from c in ge.Customer
from br in ge.Records
from p in ge.Payments
where (c.idCustomer == br.idCustomer
&& br.idHardBox == p.idHardBox)).Distinct().ToList();
defaulterCustomers = from r in queryResult
select new ReportObject
{
CustomerId = r.idCustomer,
CustomerName = r.nameCustomer,
HardBoxDateRecord = r.idHardRecord,
PaymentDate = getLatestPaymentDate(r.idCustomer),
}).Distinct().ToList();
I don't have access to your code, obviously, so try it out and tell me if it works for you!
You'll end up with an in-memory list