We have a settings file which is basically Xml that we are extending for pluggable modules we are writing. Basically we want to use our existing Xml settings but allow extension methods to be written on them. Long story short if we had an Xml file like so:
<Settings>
<SettingsOne Key1_1="Value1"
Key1_2="Value2" />
<SettingsTwo Key2_1="Value1"
Key2_2="Value2" />
</Settings>
How could we load this as an collection of SettingsEntry where SettingsEntry looked like so:
public class SettingsEntry
{
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
}
Where Section would be "SettingsOne", Key would be "Key1_1" and Value would be "Value1".
Is this even possible or am I going down a dark path?
EDIT:
OK the suggestion of Linq to Xml was a life save, I was trying to do this with XmlSerializer! Below is what I have so far, is there a way to turn this into a single select rather than two like I have below:
var root = XElement.Load(pathToXml);
var sections = from el in root.Elements()
select el.Name;
List<SettingsEntry> settings = new List<SettingsEntry>();
foreach (var item in sections)
{
var attributes = from el in root.Elements(item).Attributes()
select new SettingsEntry()
{
Section = item.LocalName,
Key = el.Name.LocalName,
Value = el.Value
};
settings.AddRange(attributes);
}
return settings;
EDIT 2:
This seems to work.
var sections = from el in root.Elements()
from a in root.Elements(el.Name).Attributes()
select new SettingsEntry()
{
Section = el.Name.LocalName,
Key = a.Name.LocalName,
Value = a.Value
};
You can do that in one LINQ query like this :
var attributes = from attribute in root.Elements().Attributes()
select new SettingsEntry()
{
Section = attribute.Parent.Name.LocalName,
Key = attribute.Name.LocalName,
Value = attribute.Value
};
return attributes.ToList();
var xml = #"
<Settings>
<SettingsOne Key1_1= ""Value1"" Key1_2= ""Value1""></SettingsOne>
<SettingsTwo Key2_1= ""Value1"" Key2_2= ""Value1""></SettingsTwo>
</Settings>"
var root = XDocument.Parse(xml);
var q = root.Elements("Settings").Descendants();
List<SettingsEntry> settings = (from el in root.Elements("Settings").Descendants()
select new SettingsEntry()
{
Section = el.Name.ToString(),
Key = el.FirstAttribute.Value,
Value = el.LastAttribute.Value
}).ToList();
You might have to play with it a little to get the exact Object you want, but this is a serious push in the right direction.
Related
I'm using LINQ together with XDocument to read a XML File. This is the code:
XDocument xml = XDocument.Load(filename);
var q = from b in xml.Descendants("product")
select new
{
name = b.Element("name").Value,
price = b.Element("price").Value,
extra = b.Element("extra1").Value,
deeplink = b.Element("deepLink").Value
};
Now the problem is, the extra1 field is not always present. There are items in the XML file without that node. If that happens it's crashing with a NullReferenceException.
Is there any possibility to include a "check if null" so I can prevent it from crashing?
Use (string) instead of .Value:
var q = from b in xml.Descendants("product")
select new
{
name = (string)b.Element("name"),
price = (double?)b.Element("price"),
extra = (string)b.Element("extra1"),
deeplink = (string)b.Element("deepLink")
};
This also works with other datatypes, including many nullable types in case the element is not always present.
You can use "null coalescing" operator:
var q = from b in xml.Descendants("product")
select new
{
name = (string)b.Element("name") ?? "Default Name",
price = (double?)b.Element("price") ?? 0.0,
extra = (string)b.Element("extra1") ?? String.Empty,
deeplink = (string)b.Element("deepLink") ?? String.Empty
};
This way, you will have full control about default value used when there's no element.
Use the following example for checking existence of any element before using that element.
if( b.Elements("extra1").Any() )
{
extra = b.Element("extra1").Value;
}
Here is sample example to read XML file using XDocument.
XDocument objBooksXML = XDocument.Load(Server.MapPath("books.xml"));
var objBooks = from book in
objBooksXML.Descendants("Book")
select new {
Title = book.Element("Title").Value,
Pages = book.Element("Pages").Value
};
Response.Write(String.Format("Total {0} books.", objBooks.Count()));
gvBooks.DataSource = objBooks;
gvBooks.DataBind();
I'm modifying .docx documents with DocumentFormat.OpenXml library. I know element ordering is important, otherwise the document will not pass schema validation and might result a document that can't be opened in Word.
Now I need to add a DocumentProtection element to DocumentSettingsPart. And I need to insert this child element in the right place inside of a parent.
The schema looks like this:
There are quite a lot of possible ordering of child elements. At the moment I'm adding this element like this:
var documentProtection = new DocumentProtection()
{
// do the configuration
};
DocumentSettingsPart settings = doc.MainDocumentPart.DocumentSettingsPart;
var rootElement = settings.RootElement;
var prevElement =
rootElement.GetFirstChild<DoNotTrackFormatting>() ??
rootElement.GetFirstChild<DoNotTrackMoves>() ??
rootElement.GetFirstChild<TrackRevisions>() ??
rootElement.GetFirstChild<RevisionView>() ??
rootElement.GetFirstChild<DocumentType>() ??
rootElement.GetFirstChild<StylePaneSortMethods>() ??
// SNIP
rootElement.GetFirstChild<Zoom>() ??
rootElement.GetFirstChild<View>() ??
(OpenXmlLeafElement)rootElement.GetFirstChild<WriteProtection>();
rootElement.InsertAfter(documentProtection, prevElement);
I.e. I'm trying to find if any possible element that should go before mine already exists in the document. And then insert DocumentProtection after that element. And given amount of elements this list gets pretty boring.
Is there a better way to add DocumentProtection so it is schema compliant and does not involve enumeration of all possible elements?
There isn't a nice way to achieve what you want. You'll have to tinker with the collection and you're responsible for keeping the order correct.
Using ILSpy on the Settings class you'll find that the implementors used a helper method SetElement<T> on the base class that takes a position and an instance to insert.
Unfortunately that helper method is marked internal so we can't leverage it if you try to subclass Settings. Instead I re-implemented the needed functionality so you'll have a subclass of Settings that does offer a property for DocumentProtection but uses the re-implemented solution to find the correct location to insert the node:
SettingsExt
public class SettingsExt: Settings
{
// contruct based on XML
public SettingsExt(string outerXml)
:base(outerXml)
{
// empty
}
public DocumentProtection DocumentProtection
{
// get is easy
get
{
return this.GetFirstChild<DocumentProtection>();
}
// reimplemented SetElement based on
// reversed engineered Settings class
set
{
// eleTagNames is a static string[] declared later
// it holds all the names of the elements in the right order
int sequenceNumber = eleTagNames
.Select((s, i) => new { s= s, idx = i })
.Where(s => s.s == "documentProtection")
.Select((s) => s.idx)
.First();
OpenXmlElement openXmlElement = this.FirstChild;
OpenXmlElement refChild = null;
while (openXmlElement != null)
{
// a bit naive
int currentSequence = eleTagNames
.Select((s, i) => new { s = s, idx = i })
.Where(s => s.s == openXmlElement.LocalName)
.Select((s) => s.idx)
.First(); ;
if (currentSequence == sequenceNumber)
{
if (openXmlElement is DocumentProtection)
{
refChild = openXmlElement.PreviousSibling();
this.RemoveChild<OpenXmlElement>(openXmlElement);
break;
}
refChild = openXmlElement;
}
else
{
if (currentSequence > sequenceNumber)
{
break;
}
refChild = openXmlElement;
}
openXmlElement = openXmlElement.NextSibling();
}
if (value != null)
{
this.InsertAfter(value, refChild);
}
}
}
// order of elements in the sequence!
static readonly string[] eleTagNames = new string[]
{
"writeProtection",
"view",
"zoom",
"removePersonalInformation",
"removeDateAndTime",
"doNotDisplayPageBoundaries",
"displayBackgroundShape",
"printPostScriptOverText",
"printFractionalCharacterWidth",
"printFormsData",
"embedTrueTypeFonts",
"embedSystemFonts",
"saveSubsetFonts",
"saveFormsData",
"mirrorMargins",
"alignBordersAndEdges",
"bordersDoNotSurroundHeader",
"bordersDoNotSurroundFooter",
"gutterAtTop",
"hideSpellingErrors",
"hideGrammaticalErrors",
"activeWritingStyle",
"proofState",
"formsDesign",
"attachedTemplate",
"linkStyles",
"stylePaneFormatFilter",
"stylePaneSortMethod",
"documentType",
"mailMerge",
"revisionView",
"trackRevisions",
"doNotTrackMoves",
"doNotTrackFormatting",
"documentProtection",
"autoFormatOverride",
"styleLockTheme",
"styleLockQFSet",
"defaultTabStop",
"autoHyphenation",
"consecutiveHyphenLimit",
"hyphenationZone",
"doNotHyphenateCaps",
"showEnvelope",
"summaryLength",
"clickAndTypeStyle",
"defaultTableStyle",
"evenAndOddHeaders",
"bookFoldRevPrinting",
"bookFoldPrinting",
"bookFoldPrintingSheets",
"drawingGridHorizontalSpacing",
"drawingGridVerticalSpacing",
"displayHorizontalDrawingGridEvery",
"displayVerticalDrawingGridEvery",
"doNotUseMarginsForDrawingGridOrigin",
"drawingGridHorizontalOrigin",
"drawingGridVerticalOrigin",
"doNotShadeFormData",
"noPunctuationKerning",
"characterSpacingControl",
"printTwoOnOne",
"strictFirstAndLastChars",
"noLineBreaksAfter",
"noLineBreaksBefore",
"savePreviewPicture",
"doNotValidateAgainstSchema",
"saveInvalidXml",
"ignoreMixedContent",
"alwaysShowPlaceholderText",
"doNotDemarcateInvalidXml",
"saveXmlDataOnly",
"useXSLTWhenSaving",
"saveThroughXslt",
"showXMLTags",
"alwaysMergeEmptyNamespace",
"updateFields",
"hdrShapeDefaults",
"footnotePr",
"endnotePr",
"compat",
"docVars",
"rsids",
"mathPr",
"uiCompat97To2003",
"attachedSchema",
"themeFontLang",
"clrSchemeMapping",
"doNotIncludeSubdocsInStats",
"doNotAutoCompressPictures",
"forceUpgrade",
"captions",
"readModeInkLockDown",
"smartTagType",
"schemaLibrary",
"shapeDefaults",
"doNotEmbedSmartTags",
"decimalSymbol",
"listSeparator",
"docId",
"discardImageEditingData",
"defaultImageDpi",
"conflictMode"};
}
A typical usage scenario with this class is as follows:
using (var doc = WordprocessingDocument.Open(#"c:\tmp\test.docx", true))
{
var documentProtection = new DocumentProtection()
{
Formatting = DocumentFormat.OpenXml.OnOffValue.FromBoolean(true)
};
DocumentSettingsPart settings = doc.MainDocumentPart.DocumentSettingsPart;
// instantiate our ExtendedSettings class based on the
// original Settings
var extset = new SettingsExt(settings.Settings.OuterXml);
// new or existing?
if (extset.DocumentProtection == null)
{
extset.DocumentProtection = documentProtection;
}
else
{
// replace existing values
}
// this is key to make sure our own DOMTree is saved!
// don't forget this
settings.Settings = extset;
}
I have an XML document from a web service that I am trying to query. However, I am not sure how to query the XML when it has elements nested inside other elements.
Here is a section of the XML file (I haven't included all of it because it's a long file):
<response>
<display_location>
<full>London, United Kingdom</full>
<city>London</city>
<state/>
<state_name>United Kingdom</state_name>
<country>UK</country>
<country_iso3166>GB</country_iso3166>
<zip>00000</zip>
<magic>553</magic>
<wmo>03772</wmo>
<latitude>51.47999954</latitude>
<longitude>-0.44999999</longitude>
<elevation>24.00000000</elevation>
</display_location>
<observation_location>
<full>London,</full>
<city>London</city>
<state/>
<country>UK</country>
<country_iso3166>GB</country_iso3166>
<latitude>51.47750092</latitude>
<longitude>-0.46138901</longitude>
<elevation>79 ft</elevation>
</observation_location>
I can query "one section at a time" but I'm constructing an object from the LINQ. For example:
var data = from i in weatherResponse.Descendants("display_location")
select new Forecast
{
DisplayFullName = i.Element("full").Value
};
var data = from i in weatherResponse.Descendants("observation_location")
select new Forecast
{
ObservationFullName = i.Element("full").Value
};
And my "Forecast" class is basically just full of properties like this:
class Forecast
{
public string DisplayFullName { get; set; };
public string ObservationFullName { get; set; };
//Lots of other properties that will be set from the XML
}
However, I need to "combine" all of the LINQ together so that I can set all the properties of the object. I have read about nested LINQ but I do not know how to apply it to this particular case.
Question: How do I go about "nesting/combining" the LINQ so that I can read the XML and then set the appropriate properties with said XML?
One possible way :
var data = from i in weatherResponse.Descendants("response")
select new Forecast
{
DisplayFullName = (string)i.Element("display_location").Element("full"),
ObservationFullName = (string)i.Element("observation_location").Element("full")
};
Another way ... I prefer using the Linq extension methods in fluent style
var results = weatherResponse.Descendants()
.SelectMany(d => d.Elements())
.Where(e => e.Name == "display_location" || e.Name == "observation_location")
.Select(e =>
{
if(e.Name == "display_location")
{
return new ForeCast{ DisplayFullName = e.Element("full").Value };
}
else if(e.Name == "observation_location")
{
return new ForeCast{ ObservationFullName = e.Element("full").Value };
}
else
{
return null;
}
});
i'm coming from PHP to C#, so please excuse some of my terminology.
Currently i'm working on a small project that requires multiple profiles to be stored in one single file, so i decided to use XML, because INI files (usually my go to guy for text based stuff) are not really supported by C#. At least not in a satisfying way.
Here the basic structure of my XML file:
<profile name="FooBar">
<btnA pressed="actionA" released="actionB" />
<btnB pressed="actionX" released="actionY" />
...
</profile>
<profile name="XYZ">
<btnA pressed="actionA" released="actionB" />
<btnB pressed="actionX" released="actionY" />
...
</profile>
In PHP i would generate an associative array with the following structure:
<?php
foo = array(
'FooBar' => array(
'btnA_pressed' => 'actionA',
'btnA_released' => 'actionB'
// ...
),
'XYZ' => array(
// ...
)
);
EDIT START
Application Class Structure:
Settings (Contains all profiles and a reference to the current profile)
Profile (See below)
The Profile class:
public class Profile
{
private string _name;
public string Name
{
get { return this._name; }
set { this._name = value;}
}
private string _btnA_pressed;
public string BtnA_Pressed { get; set; }
// and so on...
public Profile(var data) { // arg is a placeholder
// associate the data with the properties
}
}
In short, the Settings class holds all profiles and a reference to the selected profile. Access to the profile goes over Settings.CurrentProfile.propertie_Name()
EDIT END
The question is now, how do i achieve the same or a similar thing in C#? Or are there better methods of achieving the same thing?
Thanks for your help in advance!
XML structures can be manipulated very easily with LINQ2XML without the need of typed models (classes).
Reading XML file containing many profile nodes (and i assume your XML file is correct and has one root node), can look like this:
// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
foreach (var profile in profiles)
{
Console.WriteLine(profile.Attribute("name").Value);
// find all button elements
var buttons = profile
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// tag name
var name = button.Name.ToString();
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
}
}
The output is:
FooBar
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
XYZ
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
Reading a single profile XML structure from a string and then creating a new one can look like this:
var xmlCode = #"<profile name=""FooBar""><btnA pressed=""actionA"" released=""actionB"" /><btnB pressed=""actionX"" released=""actionY"" /></profile>";
try
{
// read existing XML structure
var xml = XDocument.Parse(xmlCode); // XDocument.Load("c:\\path\\to\\file.xml");
// find all button elements
var buttons = xml.Root
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// tag name
var name = button.Name.ToString();
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
}
// create xml
// root element
var newXml = new XElement("profile", new XAttribute("name", "FooBaz"),
new XElement("btnA",
new XAttribute("pressed", "actionX"),
new XAttribute("released", "actionXR")),
new XElement("btnB",
new XAttribute("pressed", "actionZ"),
new XAttribute("released", "actionZR")));
Console.WriteLine(newXml.ToString());
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
The output is:
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
<profile name="FooBaz">
<btnA pressed="actionX" released="actionXR" />
<btnB pressed="actionZ" released="actionZR" />
</profile>
You can use LINQ2XML to read the data and fill a list of objects of your Profile type like this:
// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
var listOfProfiles = new List<Profile>();
foreach (var profile in profiles)
{
var profileObject = new Profile("");
profileObject.Name = profile.Attribute("name").Value;
// find all button elements
var buttons = profile
.Elements()
.Where (e => e.Name.ToString().StartsWith("btn"));
// list elements
foreach (var button in buttons)
{
// attributes
var pressed = button.Attribute("pressed").Value;
var released = button.Attribute("released").Value;
profileObject.BtnA_Pressed = pressed;
}
listOfProfiles.Add(profileObject);
}
You can also use XML serialization - you need to describe your XML structure as a class (typed model) and deserialize (read XML file into your class) resp. serialize (write your XML structure to a file). A generic implementation of the methods for serialization resp. deserialization can look like this:
public void SerializeModel<T>(string fqfn, T entity)
{
var xmls = new XmlSerializer(entity.GetType());
var writer = new StreamWriter(fqfn);
xmls.Serialize(writer, entity);
writer.Close();
}
public T DeserializeModel<T>(string fqfn)
{
var fs = new FileStream(fqfn, FileMode.Open);
var xmls = new XmlSerializer(typeof(T));
var r = (T) xmls.Deserialize(fs);
fs.Close();
return r;
}
The typed model that describes your Profile class and the lists contained within, looks like this (note the usage of the different XML serialization attributes):
public class Profiles
{
[XmlElement(ElementName="Profile")]
public List<Profile> Profile { get; set; }
}
public class Profile
{
[XmlArray(ElementName="Buttons")]
public List<Button> Buttons { get; set; }
[XmlAttribute]
public String Name;
}
public class Button
{
[XmlAttribute]
public String Pressed { get; set; }
[XmlAttribute]
public String Released;
}
Creation of an XML file:
var profiles = new Profiles();
var profileA = new Profile();
var profileB = new Profile();
var buttonA = new Button();
var buttonB = new Button();
profileA.Buttons = new List<Button>();
profileB.Buttons = new List<Button>();
profiles.Profile = new List<Profile>();
profileA.Name = "Profile A";
profileB.Name = "Profile B";
buttonA.Pressed = "Pressed A";
buttonA.Released = "Release A";
buttonB.Pressed = "Pressed B";
buttonB.Released = "Release B";
profileA.Buttons.Add(buttonA);
profileB.Buttons.Add(buttonB);
profiles.Profile.Add(profileA);
profiles.Profile.Add(profileB);
var xmlFile = "d:\\temp\\xml\\profile_model.xml";
SerializeModel<Profiles>(xmlFile, profiles);
The new XML file looks like this (note, the structure was slightly modified because of the way XML serialization in .NET handles arrays/lists):
<?xml version="1.0" encoding="utf-8"?>
<Profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Profile Name="Profile A">
<Buttons>
<Button Released="Release A" Pressed="Pressed A" />
</Buttons>
</Profile>
<Profile Name="Profile B">
<Buttons>
<Button Released="Release B" Pressed="Pressed B" />
</Buttons>
</Profile>
</Profiles>
The file can be then read like this:
var input = DeserializeModel<Profiles>(xmlFile);
foreach (var profile in input.Profile)
{
var b = profile.Buttons.First();
Console.WriteLine(String.Format("{0} - {1} - {2}", profile.Name, b.Pressed, b.Released));
}
The output is as expected:
Profile A - Pressed A - Release A
Profile B - Pressed B - Release B
Both approaches have advantages and disadvantages.
IMO the answer to your question (changed a bit) Is XML the correct approach for saving structured data to a file? is - definitely yes! Nowadays XML is one of the standards for representing / manipulating / exchanging structured data and data generally (data kept in a string). As someone already mentioned INI files were not really meant to represent complex nested structures.
In contrast to PHP where you might be used to doing a lot of arrays and magic-string based stuff, C# is a Statically Typed language where it's usually recommended to create a proper, formally defined, structured Data Model which allows you to manipulate the Data you're dealing with in a strongly typed manner.
This means, for example, that if you're dealing with personal information related data, and you need to deal with the concepts of last name, first name, and age you will want to create a class containing these pieces of data in the form of Properties, like so:
public class Person
{
public string LastName {get;set;}
public string FirstName {get;set;}
public int Age {get;set;}
//And so on...
}
Notice how each property has an adequate Data Type that allows you to constrain what values it can contain. For example, the fact that the Age property is of type int (integer numbers) automatically means you can never have something like "abc" inside it, and code like this:
var person = new Person();
person.Age = "abc";
will also produce a compile-time error, rather than blowing up at run time, or producing any sorts of inconsistencies in stored data.
Likewise, if your Person objects (in the real world data you're trying to model) have a relation to, say an Address, you're also going to create the Address class:
public class Address
{
public string Line1 {get;set;}
public string Line2 {get;set;}
public string City {get;set;}
//And so on...
}
And then model this Person -> Address relationship by creating an additional property in the Person class:
public class Person
{
//.. All of the above.
public Address Address {get;set;}
}
Which can be illustrated with a diagram like this:
This approach has the following advantages:
It provides Compile Time checking for correctness of the code. Compile-Time errors can be trapped (and need to be corrected) very early in the development cycle. For example, you can't do something like:
person.LatsName where the property name LastName is mispelled LatsName because the compiler "knows" there is no such property in the object model and thus you recieve a compile-time error rather than having the application crash at run-time.
It provides IDE support for features such as AutoComplete because the IDE "knows" the object model you're dealing with and thus it knows what properties/methods/events (Members) every class has, and what are the expected parameters and data types for each of these.
So, to answer the overarching question, once you created a proper object model, you can use .Net's built-in Serialization/Deserialization mechanisms to transform instances of classes in your object model (with actual values and properties) to a data format that can be stored in a file on disk, such as XML.
Assuming you have a class for profile with all the relevant fields/properties, you can do
Profile profile = new Profile();
profile.actionA = "actionA"; // or whatever you have
var file = new System.IO.StreamWriter(#"c:\temp\Profile_as_xml.xml");
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Profile));
writer.Serialize(file, profile);
file.Close();
See http://msdn.microsoft.com/en-us/library/ms172873.aspx
I'm new to LINQ and Entity Framework and would appreciate some advice on the following scenario.
I have a entity model with two tables.
Travel_Request and Resource
Sample Fields
Travel_Request
Request_ID
Resource_ID
Resource
Resource_ID
Resource_Name
I would like to add the Resource_Name to the list when returning all the TRAVEL_REQUESTS
Thanks in advance
Hi you need to use the Linq join:
var data = from t in Travel_Request
join r in Resource on t.Resource_ID equals r.Resource_ID
select new
{
RequestId = t.Request_ID,
ResourceId = t.Resource_ID,
ResourceName = r.Resource_Name
};
If you already have an EF association then it could simply be:
var data = from t in Travel_Request
select new
{
RequestId = t.Request_ID,
ResourceId = t.Resource_ID,
ResourceName = t.Resource.Resource_Name
};
You will have to create a new object something like this.
var data = Travel_Request.Select(s=> new { Resource_Name = s.Recource.Resource_Name, Request_ID = s.Request_ID, Resource_ID = s.Resource_ID}).ToList();
As long as I've understood the question correctly this will work.
You can query Travel_Request entity and use the navigation propety to do that.
var resultList = DbContext.Travel_Request.Resources.where(x=>x.Resource_Name =="Your string").ToList();
I would add a model that has all three then do something like.
var TravelRequests =
from p in Travel_Request
from r in Resource.where(Res => Res.Resource_ID == p.Resource_ID)
select new TravelModel{
requestID = p.requestID,
Resource_ID = p.Resource_ID,
ResourceName = r.ResourceName
};
But thats just an example of how I would do it and there might be better ways. Also syntax might be a little off but general idea is there.
Use the Join:
Travel_Request.Join(Resource, tr => tr.ResourceId, r => r.ResourceId, (tr, r) => new { RequestId = tr.RequestId, ResourceId = tr.ResourceId, Name = r.ResourceName})
Or what a better practice would be is adding a Navigation property to TravelRequest.
TravelRequest would look like this:
int RequestId { get; set; }
int ResourceId{ get; set; }
[ForeignKey("ResourceId")]
Resource Resource { get; set; }
This way you can use Include
DBContext.TravelRequests.Include("Resource").First().Resource.Name;
Include tells EF to get the Resource with the TravelerRequest