Strong-type new object after LINQ select statement - c#

This is not a critical concept for me but I was just
wondering if I could strong-type a new object after linq select statement, rather than make it anonymous type, in C#. Here is an sample, defunct of course but speaks to the concept:
public class DisplayAddress { public int AddressId; public string ShortAddress; }
List<DisplayAddress> shortAddresses =
(from la in longAddresses
join ca in customerAddresses
on la.AddressId equals ca.AddressId
where ca.CustomerId == selectedCustomer
select new { new DisplayAddress() {AddressId = la.AddressId, ShortAddress = la.Line1 + " " + la.City + " " + la.State}}).Tolist<DisplayAddress>();

Absolutely, you can use any expression in the Select, including one that creates a new object of a type that you defined. All you need to do is removing the outer new:
select new DisplayAddress {
AddressId = la.AddressId
, ShortAddress = la.Line1 + " " + la.City + " " + la.State
}).Tolist();
Note that anonymous types are strongly typed as well. In other words, if you do
select new {
AddressId = la.AddressId
, ShortAddress = la.Line1 + " " + la.City + " " + la.State
}).Tolist();
your anonymous type would have two strongly-typed fields called AddressId and ShortAddress. The only difference is that you would need to consume anonymous objects in the context where you create them in order to preserve strong typing. In other words, you would not be able to pass the results of anonymous Select to a non-generic function without using dynamic, object, etc.

Your example code was really close. You over-complicated a few things which were probably your downfall.
In your select clause, rather than defining a new { new DisplayAddress() ... } just do new DisplayAddress(). (You were effectively boxing your DisplayAddress in another unnecessary object. There's also the compiler error of not defining what the member name of that property was.)
At the end of your query, you were doing Tolist<DisplayAddress>(). Couple of issues:
The method is ToList() and capitalization matters in C#. :)
Because you specified DisplayAddress in your Tolist<DisplayAddress>() call, it was causing a compiler error because you can't convert your anonymous type to a strong type of DisplayAddress.
After you address all of these small issues, you come up with the following:
var shortAddresses = (from la in longAddresses
join ca in customerAddresses
on la.AddressId equals ca.AddressId
where ca.CustomerId == selectedCustomer
select new DisplayAddress()
{
AddressId = la.AddressId,
ShortAddress = la.Line1 + " " + la.City + " " + la.State
}).ToList();

Related

Nested Lists in Unity 3d- How do I do this?

Bryce: Here are my current functions. With the list in the class, I'm not quite sure how to modify my code.
public void GetMembers()
{
DatabaseManager.Instance.SQLiteInit();
MemberList.Clear();
MemberList= DatabaseManager.Instance.MakeMembersList();
Debug.Log("How many in the list " + MemberList.Count);
ShowAllMembers();
}
public void GetEquipment()
{
DatabaseManager.Instance.SQLiteInit();
EquipmentList.Clear();
EquipmentList= DatabaseManager.Instance.MakeEquipmentList();
Debug.Log("How many in the list " + EquipmentList.Count);
ShowAllEquipment();
}
Also thought you should see the database function being called.
public List<NewEquipmentClass> MakeEquipmentList()
{
EquipmentList.Clear();
mConnection.Open();
mSQLString = "SELECT * FROM " + SQL_TABLE_EQUIPMENT + " ORDER BY " + COL_EQUIPMENT_ID;
mCommand.CommandText = mSQLString;
mCommand.ExecuteNonQuery();
mReader = mCommand.ExecuteReader();
while (mReader.Read())
{
EquipmentList.Add(new Equipment(mReader.GetString(0),
mReader.GetString(1)));
Debug.Log(mReader.GetString(0) + mReader.GetString(1));
}
mReader.Close();
mConnection.Close();
return EquipmentList;
}
Thanks!
This is the result I am looking for:
Member Name
Member's Equipment
Member's Equipment
Member's Equipment
Member Name
Member's Equipment...
Etc.
I have two lists, one for members and one for equipment. What is the best way to get the type of results above?
Thanks!
It looks like you want to create a class called Member that looks something like this
class Member {
string name;
List<Equipment> equipment;
}
where Equipment could be an object with a name and stats or whatever you need. And then have a list of them like
List<Member> members;
Obviously you'd want getters/setters/constructor etc. but if implementing this isn't clear to you I'd recommend some fundamentals of c# or Object Oriented learning.

How to Join two IEnumerables with anonymous types?

I'm using Linq-to-Xml to create two IEnumerables but I want to combine the results of the second list with the first list. When I use the .Concat() I get the following error:
'IQueryable<>' does not contain a definition for 'Concat' and the best extension method overload 'ParallelEnumerable.Concat<>(ParallelQuery<>, IEnumerable<>)' requires a receiver of type 'ParallelQuery<>'
The two lists I'm trying to .Concat() are here:
var findingDetails = from f in element.Elements(ns + "Group")
select new
{
testID = (string)f.Attribute("id").Value,
title = (string)f.Element(ns + "title"),
idrefFD = (string)f.Element(ns + "Rule").Attribute("id").Value,
severity = (string)f.Element(ns + "Rule").Attribute("severity").Value,
description = (string)f.Element(ns + "Rule").Element(ns + "description"),
fixText = (string)f.Element(ns + "Rule").Element(ns + "fixtext")
};
var getStatus = from gs in element.Descendants(ns + "rule-result")
select new
{
idrefStatus = (string)gs.Attribute("idref").Value,
result = (string)gs.Element(ns + "result"),
dateTime = (string)gs.Attribute("time")
};
The error is generated on the findingDetails usage here:
var combined = findingDetails.Concat(getStatus);
What I'm trying to get is a var with that has everything from findingDetails + getStatus.result and getStatus.dateTime, in one place. This why I only have to iterate over one foreach() loop to access all of the values instead of using a nested foreach() loop.
Sample XML Document:
<?xml version="1.0" encoding="UTF-8"?>
<cdf:Benchmark style="SCAP_1.1" resolved="1" id="RHEL_6_STIG" xsi:schemaLocation="http://checklists.nist.gov/xccdf/1.1 http://nvd.nist.gov/schema/xccdf-1.1.4.xsd http://cpe.mitre.org/dictionary/2.0 http://scap.nist.gov/schema/cpe/2.2/cpe-dictionary_2.2.xsd" xmlns:cdf="http://checklists.nist.gov/xccdf/1.1" xmlns:cpe="http://cpe.mitre.org/dictionary/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<cdf:status date="2016-04-22">accepted</cdf:status>
<cdf:title>Red Hat Enterprise Linux 6 Security Technical Implementation Guide</cdf:title>
<cdf:description>The Red Hat Enterprise Linux 6 Security Technical Implementation Guide (STIG) is published as a tool to improve the security of Department of Defense (DoD) information systems. Comments or proposed revisions to this document should be sent via e-mail to the following address: disa.stig_spt#mail.mil.</cdf:description>
<cdf:notice id="terms-of-use"></cdf:notice>
<cdf:reference href="http://iase.disa.mil">
<dc:publisher>DISA</dc:publisher>
<dc:source>STIG.DOD.MIL</dc:source>
</cdf:reference>
<cdf:plain-text id="release-info">Release: 11 Benchmark Date: 22 Apr 2016</cdf:plain-text>
<cdf:platform idref="cpe:/o:redhat:enterprise_linux:6"></cdf:platform>
<cdf:version>1</cdf:version>
<cdf:Profile id="MAC-1_Classified">
<cdf:title>I - Mission Critical Classified</cdf:title>
</cdf:Profile>
<cdf:Value id="var_umask_for_daemons">
<cdf:title>daemon umask</cdf:title>
<cdf:description>Enter umask for daemons</cdf:description>
<cdf:value>022</cdf:value>
<cdf:value selector="022">022</cdf:value>
<cdf:value selector="027">027</cdf:value>
</cdf:Value>
<cdf:Group id="V-7055">
<cdf:title>APPNET0031 No Strong Name Verification</cdf:title>
<cdf:description><GroupDescription></GroupDescription></cdf:description>
<cdf:Rule weight="10.0" id="SV-7438r2_rule" severity="medium">
<cdf:version>APPNET0031</cdf:version>
<cdf:title>Digital signatures assigned to strongly named assemblies must be verified.</cdf:title>
<cdf:description><VulnDiscussion>A strong name consists of the assembly's identity, simple text name, version number, and culture information (if provided)—plus a public key and a digital signature. Strong names serve to identify the author of the code. If digital signatures used to sign strong name assemblies are not verified, any self signed code can be impersonated. This can lead to a loss of system integrity. </VulnDiscussion><FalsePositives></FalsePositives><FalseNegatives></FalseNegatives><Documentable>false</Documentable><Mitigations></Mitigations><SeverityOverrideGuidance></SeverityOverrideGuidance><PotentialImpacts></PotentialImpacts><ThirdPartyTools></ThirdPartyTools><MitigationControl></MitigationControl><Responsibility>System Administrator</Responsibility><IAControls>DCSL-1</IAControls></cdf:description>
<cdf:reference>
<dc:publisher>DISA</dc:publisher>
<dc:identifier>2030</dc:identifier>
<dc:type>DPMS Target</dc:type>
</cdf:reference>
<cdf:fixtext fixref="F-12596r7_fix">Use regedit to remove the values stored in Windows registry key hKLM\Software\Microsoft\StrongName\Verification. There should be no assemblies or hash values listed under this registry key. All assemblies must require strong name verification in a production environment. Strong name assemblies that do not require verification in a development or test environment must have documented approvals from the IAO.</cdf:fixtext>
<cdf:fix id="F-12596r7_fix"></cdf:fix>
<cdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<cdf:check-content-ref href="U_Microsoft_DotNet_Framework_4_V1R4_STIG_SCAP_1-1_Benchmark-oval.xml" name="oval:mil.disa.fso.dotnet:def:2"></cdf:check-content-ref>
</cdf:check>
</cdf:Rule>
</cdf:Group>
<cdf:TestResult start-time="2016-07-20T11:59:59" version="1" test-system="cpe:/a:spawar:scc:4.1" end-time="2016-07-20T12:00:50" id="U_Microsoft_DotNet_Framework_4_V1R4_STIG_SCAP_1-1_Benchmark-xccdf.xml---MAC-2_Classified-1">
<cdf:benchmark href="U_Microsoft_DotNet_Framework_4_V1R4_STIG_SCAP_1-1_Benchmark-xccdf.xml"></cdf:benchmark>
<cdf:organization>SPAWAR Systems Center Atlantic</cdf:organization>
<cdf:identity privileged="true" authenticated="true">CCSAdmin</cdf:identity>
<cdf:profile idref="MAC-2_Classified"></cdf:profile>
<cdf:target>hostname</cdf:target>
<cdf:target-address>192.168.1.000</cdf:target-address>
<cdf:target-facts>
<cdf:fact name="urn:scap:fact:asset:identifier:host_name" type="string">hostname</cdf:fact>
<cdf:fact name="urn:scap:fact:asset:identifier:domain" type="string">.net</cdf:fact>
<cdf:fact name="urn:scap:fact:asset:identifier:fqdn" type="string">hostname.net</cdf:fact>
<cdf:fact name="urn:scap:fact:asset:identifier:os_name" type="string">Windows 7 Enterprise</cdf:fact>
<cdf:fact name="urn:scap:fact:asset:identifier:os_service_pack" type="string">Service Pack 1</cdf:fact>
<cdf:fact name="urn:scap:fact:asset:identifier:ipv4" type="string">192.168.1.000</cdf:fact>
</cdf:target-facts>
<cdf:platform idref="cpe:/a:microsoft:.net_framework:4.0"></cdf:platform>
<cdf:rule-result version="APPNET0031" time="2016-07-20T11:59:59" idref="SV-7438r2_rule" weight="10.0" severity="medium">
<cdf:result>pass</cdf:result>
<cdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<cdf:check-content-ref href="U_Microsoft_DotNet_Framework_4_V1R4_STIG_SCAP_1-1_Benchmark-oval.xml" name="oval:mil.disa.fso.dotnet:def:2"></cdf:check-content-ref>
</cdf:check>
</cdf:rule-result>
<cdf:rule-result version="APPNET0046" time="2016-07-20T11:59:59" idref="SV-7444r3_rule" weight="10.0" severity="medium">
<cdf:result>fail</cdf:result>
<cdf:fix id="F-12602r12_fix"></cdf:fix>
<cdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<cdf:check-content-ref href="U_Microsoft_DotNet_Framework_4_V1R4_STIG_SCAP_1-1_Benchmark-oval.xml" name="oval:mil.disa.fso.dotnet:def:15"></cdf:check-content-ref>
</cdf:check>
</cdf:rule-result>
</cdf:TestResult>
</cdf:Benchmark>
I changed the queries and now both look like this:
var findingDetails = from f in element.Elements(ns + "Group")
select new
{
idrefStatus = (string)"",
result = (string)"",
dateTime = (string)"",
testID = (string)f.Attribute("id").Value,
title = (string)f.Element(ns + "title"),
idref = (string)f.Element(ns + "Rule").Attribute("id").Value,
severity = (string)f.Element(ns + "Rule").Attribute("severity").Value,
description = (string)f.Element(ns + "Rule").Element(ns + "description"),
fixText = (string)f.Element(ns + "Rule").Element(ns + "fixtext")
};
var getStatus = from gs in element.Descendants(ns + "rule-result")
select new
{
idrefStatus = (string)gs.Attribute("idref").Value,
result = (string)gs.Element(ns + "result"),
dateTime = (string)gs.Attribute("time"),
testID = (string)"",
title = (string)"",
idref = (string)"",
severity = (string)"",
description = (string)"",
fixText = (string)""
};
var combined = findingDetails.Concat(getStatus);
But now the output looks like this
foreach (var cf in combined)
{
Console.WriteLine(cf.idref + ", " + cf.result);
}
SV-7438r2_rule,
SV-7444r3_rule,
SV-40966r1_rule,
SV-41075r1_rule,
, pass
, fail
, pass
, pass
Whereas, I'm trying to get something like this:
SV-7438r2_rule, pass
SV-7444r3_rule, fail
SV-40966r1_rule, pass
SV-41075r1_rule, pass
From your expected output ("Whereas, I'm trying to get something like this:...") and data you added it seems like what you are looking for is a join and not to concat the lists (concat will give you n*m records)
This is what it seems you are looking for:
XNamespace ns = "http://checklists.nist.gov/xccdf/1.1";
var findingDetails = (from f in XDocument.Load("data.xml").Descendants(ns + "Group")
let rule = f.Element(ns + "Rule")
select new
{
testID = (string)f.Attribute("id").Value,
title = (string)f.Element(ns + "title"),
idref = (string)rule.Attribute("id").Value,
severity = (string)rule.Attribute("severity").Value,
description = (string)rule.Element(ns + "description"),
fixText = (string)rule.Element(ns + "fixtext")
}).ToList();
var getStatus = (from gs in XDocument.Load("data.xml").Descendants(ns + "rule-result")
select new
{
idrefStatus = (string)gs.Attribute("idref").Value,
result = (string)gs.Element(ns + "result"),
dateTime = (string)gs.Attribute("time"),
}).ToList();
var result = (from d in findingDetails
join f in getStatus on d.idref equals f.idrefStatus
select new { d, f }).ToList();
If you might have Groups that do not have a matching rule-result then use left join instead
You can concat two anonymous types if they are declared with exactly the same properties.
You can't concat two different types, but you can cast them to object and then concat:
List<int> ints = new List<int>() { 1, 2, 3 };
List<string> strings = new List<string> { "a", "b", "c" };
ints.Cast<object>().Concat( strings.Cast<object>() );

How to compare selected items of listbox to those in database and delete the ones that aren't selected

I'm having a bit of trouble getting my code to work. I'm retrieving all of my actor objects from my database, which are the castmembers of a certain movie, using LINQ to SQL. I've checked the output and they're just fine.
Because I had to use a dictionary to show the actors names as a whole, I need to compare whether the selected values of the listbox are the same as the combination of the First- and LastName of the actor.
The first thing I'm doing is going through all the selected items in my listbox. Next, I want to compare them to the First and LastName of the actorsm which I retrieved using LINQ. But it doesn't work like I want it to.
Example: Movie is Pulp Fiction and the Actors related to the movie are Uma Thurman, Samuel L. Jackson and John Travolta. When I run this code I get a total of 3 MessageBoxes with the following output:
[4, Uma Thurman] Matches Uma Thurman
[5, Samuel L. Jackson] Matches Uma Thurman
[6, John Travolta] Matches Uma Thurman
Though what I really want to achieve is that it breaks out of the loop after finding Uma and then get a messagebox saying:
[5, Samuel L. Jackson] Matches Samuel L. Jackson. and so forth. I want to do this since I want to delete and/or insert actors that are selected/deselected from the movie.
var deleteMovieActors = db.MovieActors.Where(mid => mid.Movie_MovieId == MovieId).Select(a => a.Actor);
foreach (var item in lstbActors.SelectedItems)
{
foreach (Actor a in deleteMovieActors)
{
if (lstbActors.SelectedItem.ToString().Contains(a.FirstName + " " + a.LastName))
{
MessageBox.Show(item.ToString() + " Matches " + a.FirstName + " " + a.LastName);
break;
}
}
}
Here's how I create my listbox:
private void InitializeListBox()
{
var actors = new Dictionary<int, string>();
foreach (var actor in db.Actors.ToList())
{
actors.Add(actor.ActorId, actor.FirstName + " " + actor.LastName);
}
lstbActors.DataSource = actors.ToList();
lstbActors.ValueMember = "Key";
lstbActors.DisplayMember = "Value";
lstbActors.SelectedIndex = -1;
// Get Actors by MovieId
var MAct = from ma in db.MovieActors
where ma.Movie_MovieId == MovieId
select ma;
List<Actor> act = new List<Actor>();
foreach (var ma in MAct)
{
act.Add(db.Actors.Where(a => a.ActorId == ma.Actor_ActorId).Single());
}
foreach (Actor a in act)
{
int index = lstbActors.FindStringExact(a.FirstName + " " + a.LastName);
if (index != -1)
{
lstbActors.SetSelected(index, true);
}
}
}
The problem is located in the condition of the IF statement. The SelectedItem property returns the first occurence over and over in the loop.
if (lstbActors.SelectedItem.ToString().Contains(a.FirstName + " " + a.LastName))
{
MessageBox.Show(item.ToString() + " Matches " + a.FirstName + " " + a.LastName);
break;
}
When I changed the code as following, it works:
item.ToString().Contains(a.FirstName + " " + a.LastName
If you want exact matches of First and Last Name use string.Equals() rather than contains because contains return all of the string which contains the specified keyword e.g if you use contains for string "Hello" on strings "Hello" and "Hello World", then it will give you both Hello and Hello World.

where clause in LINQ to Entites DataBind

I'm trying to add a where clause to an existing LINQ DataBind but nothing I do works. The where clause I want to add checks if in the table refAuthSigner the column IsActive == 1.
Here's my existing Query:
// populates Authorized Signer dropdownlist
using (dbPSREntities10 myEntities = new dbPSREntities10())
{
var allSigners = from refAuthSigner in myEntities.refAuthSigners <--- where clause somewhere around here??
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
ddlAuthSigners.DataSource = allSigners;
ddlAuthSigners.DataValueField = "refAuthSignerID";
ddlAuthSigners.DataTextField = "refAuthSignerName";
ddlAuthSigners.DataBind();
}
I want to add a where clause which is something like:
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive == 1
This code isn't right and just wondering how I would incorporate the where clause into the code. Thanks!
Simply use:
where refAuthSigner.IsActive
Since it's a boolean value you cannot compare it to an integer. It is true or false, not 1 or 0. (Some langauges conflate the two, C# is not one of them.)
There is no need to compare IsActive to anything. where needs a boolean value, and IsActive is a boolean value. You already have exactly what you need.
You could make the statement:
var allsigners = refAuthSigner.Where(x => x.refAuthSigner.IsActive)
Try this:
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
Operator of '==' cannot be applied to operands of type 'bool' and 'int'. IsActive is type bit in SqlServer
If this is the error you are getting try using Any instead of Where as it returns bool
// populates Authorized Signer dropdownlist
using (dbPSREntities10 myEntities = new dbPSREntities10())
{
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
ddlAuthSigners.DataSource = allSigners;
ddlAuthSigners.DataValueField = "refAuthSignerID";
ddlAuthSigners.DataTextField = "refAuthSignerName";
ddlAuthSigners.DataBind();
}

Object Reference error in LINQ

I had applied the following code :
var country = from cnty in this.GetAll<CompanyDefinition>().ToList()
where cnty.IsImported = true
select new {
CompanyDefinitionID = cnty.CompanyDefinitionID
, CompanyDefinitionName = cnty.Company.CompanyName + "(" + cnty.Country.CountryCode + "," + cnty.NaicsCode.NaicsCode1 + ")"
};
And I am getting Object Reference error. Its pointing to "select new". Whats the correct way?
The problem is Company, Country or NaicsCode is null, you would need to check this before attempting to access their properties. For example, you could re-write your query as:
var country = from cnty in this.GetAll<CompanyDefinition>()
where cnty.IsImported && cnty.Company != null && cnty.Country != null && cnty.NaicsCode != null
select new {
...
}
If you are employing lazy loading, then using ToList() method is not proper. After calling ToList(), IQueryable<> object is materialized to IEnumerable<>; thus database is not queried for Company or Country references. Try removing ToList() function.

Categories