How to save a large nhibernate collection without causing OutOfMemoryException - c#

How do I save a large collection with NHibernate which has elements that surpass the amount of memory allowed for the process?
I am trying to save a Video object with nhibernate which has a large number of Screenshots (see below for code). Each Screenshot contains a byte[], so after nhibernate tries to save 10,000 or so records at once, an OutOfMemoryException is thrown. Normally I would try to break up the save and flush the session after every 500 or so records, but in this case, I need to save the collection because it automatically saves the SortOrder and VideoId for me (without the Screenshot having to know that it was a part of a Video). What is the best approach given my situation? Is there a way to break up this save without forcing the Screenshot to have knowledge of its parent Video?
For your reference, here is the code from the simple sample I created:
public class Video
{
public long Id { get; set; }
public string Name { get; set; }
public Video()
{
Screenshots = new ArrayList();
}
public IList Screenshots { get; set; }
}
public class Screenshot
{
public long Id { get; set; }
public byte[] Data { get; set; }
}
And mappings:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SavingScreenshotsTrial"
namespace="SavingScreenshotsTrial"
default-access="property">
<class name="Screenshot"
lazy="false">
<id name="Id"
type="Int64">
<generator class="hilo"/>
</id>
<property name="Data" column="Data" type="BinaryBlob" length="2147483647" not-null="true" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SavingScreenshotsTrial"
namespace="SavingScreenshotsTrial" >
<class name="Video"
lazy="false"
table="Video"
discriminator-value="0"
abstract="true">
<id name="Id"
type="Int64"
access="property">
<generator class="hilo"/>
</id>
<property name="Name" />
<list name="Screenshots"
cascade="all-delete-orphan"
lazy="false">
<key column="VideoId" />
<index column="SortOrder" />
<one-to-many class="Screenshot" />
</list>
</class>
</hibernate-mapping>
When I try to save a Video with 10000 screenshots, it throws an OutOfMemoryException. Here is the code I'm using:
using (var session = CreateSession())
{
Video video = new Video();
for (int i = 0; i < 10000; i++)
{
video.Screenshots.Add(new Screenshot() {Data = camera.TakeScreenshot(resolution)});
}
session.SaveOrUpdate(video);
}

For this reason, we have typically had the child entity reference the parent rather than vice versa.

Create a custom type by using AbstractType and IParameterizedType these are in NHibernate.Type namespace. Use stateless session and provide batch size.

The chapter 13 of nhibernate documentation handle this issue.
"A naive approach to inserting 100 000 rows in the database using NHibernate might look like this:
using (ISession session = sessionFactory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
for (int i = 0; i < 100000; i++)
{
Customer customer = new Customer(.....);
session.Save(customer);
}
tx.Commit();
}
This would fall over with an OutOfMemoryException somewhere around the 50 000th row[...]"
To resume... the solution is work with batch size and no second level cache by setting this properties:
Batch size:
adonet.batch_size 20
Second level cache:
cache.use_second_level_cache false
It should be enougth to solve OutOfMemoryException.
More datails at documentation reference: http://nhibernate.info/previous-doc/v5.0/single/nhibernate_reference.pdf

Related

C# Convert XML file to Multiple Polygon Objects

After converting multiple MapInfo files into a unique Shapefile, and then converting that file again to .KML, I got the following .XML file. My idea is to extract each set of 'coordinates' sections, and build polygons using them.
Other attempted solution:
Given the excessive time facing this blockage, I tried obtaining each pair of 'coordinates' tags and using Substring to get the coordinates. Unfortunately given the size of the file (>400 MB) this dirty approach is not practical.
Xml file
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document id="root_doc">
<Schema id="PruebaKML4g.schema">
<SimpleField name="FID" type="float"/>
<SimpleField name="REGION" type="float"/>
<SimpleField name="NOMBRE" type="string"/>
<SimpleField name="layer" type="string"/>
<SimpleField name="path" type="string"/>
</Schema>
<Document id="PruebaKML4g">
<name>PruebaKML4g</name>
<Placemark id="PruebaKML4g.1">
<ExtendedData>
<SchemaData schemaUrl="#PruebaKML4g.schema">
<SimpleData name="FID">5</SimpleData>
<SimpleData name="REGION">1</SimpleData>
<SimpleData name="NOMBRE">BAJA CALIFORNIA</SimpleData>
<SimpleData name="layer">LBS_REGION_1_region</SimpleData>
<SimpleData name="path">C:/Files/LBS_REGION_1_region.shp</SimpleData>
</SchemaData>
</ExtendedData>
<MultiGeometry>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-105.258751,21.782028,0
-105.247174,21.81173,0
-105.241826,21.809401,0
-105.236994,21.806241,0
-105.232822,21.802344,0
-105.229439,21.79783,0
-105.228552,21.796052,0
-105.228974,21.795899,0
-105.230294,21.79522,0
-105.231872,21.79511,0
-105.234048,21.79431,0
-105.235131,21.794083,0
-105.236824,21.793857,0
-105.238518,21.793295,0
-105.239365,21.792389,0
-105.240327,21.790914,0
-105.242379,21.79046,0
-105.243829,21.790459,0
-105.245644,21.788766,0
-105.247331,21.785709,0
-105.24817,21.783115,0
-105.248701,21.780372,0
-105.258751,21.782028,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
...
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-103.704559,20.767933,0
-103.702714,20.773608,0
-103.701694,20.77322,0
-103.700762,20.772672,0
-103.699944,20.77198,0
-103.699267,20.771165,0
-103.698751,20.770252,0
-103.698411,20.769268,0
-103.698258,20.768243,0
-103.698297,20.76721,0
-103.704559,20.767933,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-105.160778,20.766278,0
-105.162411,20.77201,0
-105.161328,20.77219,0
-105.160228,20.77219,0
-105.159145,20.77201,0
-105.158111,20.771656,0
-105.157159,20.771139,0
-105.156317,20.770474,0
-105.15561,20.769682,0
-105.15506,20.768786,0
-105.160778,20.766278,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
-117.125814,32.524285,0
-117.125516,32.524512,0
-117.125142,32.524428,0
-117.124876,32.524169,0
-117.124754,32.524513,0
-117.124784,32.525361,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</MultiGeometry>
</Placemark>
</Document>
</Document>
</kml>
I tried to use the following code:
Main
public T DeserializeToObject<T>(string filepath) where T : class
{
System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (StreamReader streamReader = new StreamReader(filepath))
{
return (T)xmlSerializer.Deserialize(streamReader);
}
}
private void Form1_Load(object sender, EventArgs e)
{
String pathKml = #"C:\PruebaKML4g.kml";
List<Kml> elementsList = DeserializeToObject<List<Kml>>(pathKml);
}
Kml.cs
/*[XmlRoot(ElementName = "kml")] changed by Mike Clark suggestion*/
[XmlRoot(ElementName = "kml", Namespace = "http://www.opengis.net/kml/2.2")]
public class Kml
{
public List<Polygon> polygons = new List<Polygon>();
}
public class Polygon
{
[XmlAttribute("outerBoundaryIs")]
public String outerBoundaryIs { get; set; }
[XmlAttribute("linearRing")]
public String linearRing { get; set; }
[XmlAttribute("coordinates")]
public String coordinates { get; set; }
}
However, the SimpleData elements in the XML file appear to be interfering with my parsing, generating the following error
InvalidOperationException: xmlns='http://www.opengis.net/kml/2.2'> was not expected.
Any clue about where my mistake is will be appreciated.
With all those conversion steps, perhaps the XML file is malformed? Or maybe a memory error with so much data? Try parsing the file with a low-memory requirement SAX parser to let it find any syntactical errors that might be buried deep in the file. Do you have Python installed?
python -c "import xml.sax;p=xml.sax.make_parser();p.parse(r'yourfile.xml')"
Change yourfile.xml to the correct path and filename of your XML file.
If it prints nothing, the file is syntactically valid. If it prints an error, try to use the line:column info in the error to spot the error in your XML.
Part 2:
List<Kml> elementsList = DeserializeToObject<List<Kml>>(pathKml);
might be wrong. XML documents can have one and only one root <element> (in this case, <kml>) so I think having a list of Kml instances will not make make sense for the parser. Try this instead:
Kml root = DeserializeToObject<Kml>(pathKml);
But that is a simple problem compared to the next problem, which is that I think your C# class structure needs to mirror exactly the hierarchical structure of the XML. The polygons are under this hierarchy:
kml > Document > Document > Placemark > MultiGeometry
which means you would need something like
class Kml {
Document Document;
}
class Document {
Document Document;
Placemark Placemark;
}
class Placemark {
Polygon[] MultiGeometry;
}
class Polygon {
OuterBoundaryIs outerBoundaryIs;
}
class OuterBoundaryIs {
LinearRing LinearRing;
}
class LinearRing {
string coordinates;
}
Then you would need something like
var polygons = kml.Document.Document.Placemark.MultiGeometry;
for(int i = 0; i < polygons.Length; i++) {
var polygon = polygons[i];
string coordinates = polygon.outerBoundaryIs.LinearRing.coordinates;
// do something with coordinates
}
By the way, a better kind of parser for this type of thing would be an XPath parser which can avoid the need to model the XML structure with C# classes. It takes a little practice and research to craft an XPath query, but the resulting code is cleaner, and it's a good skill to have some experience with. More XPath see:
https://stackoverflow.com/a/16012736/11611195
https://learn.microsoft.com/en-us/dotnet/standard/data/xml/select-nodes-using-xpath-navigation

Apache Ignite, C#: Distributed Computing - Topology projection error

I am trying to emulate the Distributed Computing examples in the Apache doc, specifically the Broadcasting example.
I start the cluster remotely, where 2 nodes make up the cluster with the following XML configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<!-- In distributed environment, replace with actual host IP address. -->
<value>[remoteHost]:47500..47509</value>
<value>[localHost1]:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
Then, I start a node locally with an IP address of [localHost1]:
class PrintNodeIdAction : IComputeAction
{
public void Invoke()
{
Console.WriteLine("Hello node: " +
Ignition.GetIgnite().GetCluster().GetLocalNode().Id);
}
}
static void Main(string[] args)
{
var cfg = new IgniteConfiguration
{
DiscoverySpi = new TcpDiscoverySpi
{
IpFinder = new TcpDiscoveryStaticIpFinder
{
Endpoints = new[] { "[remoteHost]", "[remoteHost]:47500..47509" }
}
}
};
using (IIgnite ignite = Ignition.Start(cfg))
{
// Limit broadcast to remote nodes only.
var compute = ignite.GetCluster().ForRemotes().GetCompute();
// Print out hello message on remote nodes in the cluster group.
compute.Broadcast(new PrintNodeIdAction());
}
}
However, I run into the following two (2) errors after starting the local node:
**1 of 2**
ClusterGroupEmptyException: Topology projection is empty.
**2 of 2**
JavaException: class org.apache.ignite.internal.cluster.ClusterGroupEmptyCheckedException: Topology projection is empty.
at org.apache.ignite.internal.processors.task.GridTaskWorker.getTaskTopology(GridTaskWorker.java:688)
at org.apache.ignite.internal.processors.task.GridTaskWorker.body(GridTaskWorker.java:503)
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:120)
at org.apache.ignite.internal.processors.task.GridTaskProcessor.startTask(GridTaskProcessor.java:830)
at org.apache.ignite.internal.processors.task.GridTaskProcessor.execute(GridTaskProcessor.java:498)
at org.apache.ignite.internal.processors.task.GridTaskProcessor.execute(GridTaskProcessor.java:466)
at org.apache.ignite.internal.IgniteComputeImpl.executeAsync0(IgniteComputeImpl.java:564)
at org.apache.ignite.internal.processors.platform.compute.PlatformCompute.executeNative0(PlatformCompute.java:329)
at org.apache.ignite.internal.processors.platform.compute.PlatformCompute.processClosures(PlatformCompute.java:294)
at org.apache.ignite.internal.processors.platform.compute.PlatformCompute.processInStreamOutObject(PlatformCompute.java:140)
at org.apache.ignite.internal.processors.platform.PlatformTargetProxyImpl.inStreamOutObject(PlatformTargetProxyImpl.java:79)

How to insert into column where otherColumn Equal someValue using Nhibernate

First of all , excuse my low knowledge in Hibernate (I'm a sql fan) , I've done many research and I just can't find how to properly do this below
What I would like to do :I Have a table called ClassCodes and I want to insert each Equivalence code next to his original code
So my 2 columns are Originalcode and Equivalencecodes (Let's assume Originalcode are already filled)
Here is the function I would love to have help
public void addEquivalenceCodes(string Code, string EquivalenceCode)
try
{
using (ISession session = OpenSession())
{
using (ITransaction transaction =session.BeginTransaction())
{
//**Here is what I don't know how to write properly in hibernate
String hql = "INSERT INTO ClassCodes(CodeEquiv)" + "VALUES ("+EquivalenceCode+") WHERE Originalcode = "+Code+";
Query query = session.createQuery(hql);
transaction.Commit();
}
}
}
catch (Exception e) { Console.WriteLine(e); }
}
Here is my mapping , to add more visual help
<class name="ClassCodes, table="[T0101_ClassCode]" lazy="false">
<id name="Id" column="[Id]">
<generator class="native" />
</id>
<property name="OriginalCode" column="[OriginalCode]" />
<property name="EquivalanceCode" column="[EquivalanceCode]" />
etc...
I appreciate all guides , tips and explication I can get !
it's not an insert it's an update.
using (var session = new Configuration().Configure().BuildSessionFactory().OpenSession())
{
ClassCodes classcodes=session.Get<ClassCodes>(Originalcode);
classcodes.EquivalanceCode="EquivalanceCode value";
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(classcodes);
transaction.Commit();
}
}

NHibernate.Exceptions.GenericADOException : could not execute query

I have a legacy application (vfp 8) that I need to pull data from (no inserts). I am using the Accnum field as the primary key, it is defined in the table as character 11.
Factory configuration:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<reflection-optimizer use="false" />
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.GenericDialect</property>
<property name="connection.driver_class">NHibernate.Driver.OleDbDriver</property>
<property name="connection.connection_string">Provider=VFPOLEDB.1;Data Source=C:\Analysis\Quantium\development\RD warehouse\_RDAUWH\Data;Collating Sequence=MACHINE</property>
<property name="show_sql">false</property>
</session-factory>
</hibernate-configuration>
This is my mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="RDLabels"
namespace="RDLabels.Domain">
<class name="CustMast">
<id name="Accnum" column="Accnum" type="string">
<generator class="assigned"/>
</id>
<property name="Fullname" />
<property name="Add" />
<property name="State" />
</class>
</hibernate-mapping>
The class:
public class CustMast
{
private string _accnum;
public virtual string Accnum
{
get { return _accnum; }
set { _accnum = value; }
}
private string _fullname;
public virtual string Fullname
{
get { return _fullname; }
set { _fullname = value; }
}
private string _add;
public virtual string Add
{
get { return _add; }
set { _add = value; }
}
private string _state;
public virtual string State
{
get { return _state; }
set { _state = value; }
}
}
Here is the code that gets the record:
public CustMast GetByAccnum(String accnum)
{
using (ISession session = NHibernateHelper.OpenSession())
{
CustMast custMast = session
.CreateCriteria(typeof(CustMast))
.Add(Restrictions.Eq("Accnum", accnum))
.UniqueResult<CustMast>();
return custMast;
}
}
The full error is:
NHibernate.Exceptions.GenericADOException : could not execute query
[ SELECT this_.Accnum as Accnum0_0_, this_.Fullname as Fullname0_0_, this_.Add as Add0_0_, this_.State as State0_0_ FROM CustMast this_ WHERE this_.Accnum = ? ]
Name:cp0 - Value:00059337444
[SQL: SELECT this_.Accnum as Accnum0_0_, this_.Fullname as Fullname0_0_, this_.Add as Add0_0_, this_.State as State0_0_ FROM CustMast this_ WHERE this_.Accnum = ?]
----> System.IndexOutOfRangeException : Invalid index 0 for this OleDbParameterCollection with Count=0. - d:\CSharp\NH\NH\nhibernate\src\NHibernate\Loader\Loader.cs:1590
Running NHibernate Profiler it shows:
WARN:
reflection-optimizer property is ignored out of application configuration file.
WARN:
System.IndexOutOfRangeException: Invalid index 0 for this OleDbParameterCollection with Count=0.
at System.Data.OleDb.OleDbParameterCollection.RangeCheck(Int32 index)
at System.Data.OleDb.OleDbParameterCollection.GetParameter(Int32 index)
at System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index)
at NHibernate.Driver.DriverBase.ExpandQueryParameters(IDbCommand cmd, SqlString sqlString) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Driver\DriverBase.cs:line 235
at NHibernate.AdoNet.AbstractBatcher.ExpandQueryParameters(IDbCommand cmd, SqlString sqlString) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\AdoNet\AbstractBatcher.cs:line 232
at NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters, Boolean scroll, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Loader\Loader.cs:line 1152
ERROR:
Invalid index 0 for this OleDbParameterCollection with Count=0.
I was struggling with my linq queries throwing the same error whenever i passed them a parameter. If i didn't pass any parameters and did a session.Query() they would work fine.
I struggled with this for days but i found this Nhibernate jira ticket here . It explains an apparent problem with SQLParameters and the Iseries Db2 provider.
I understand you're using a different provider but you might benefit from just downloading the latest Nhibernate core source code, building it, and referencing the latest version in your project. It fixed my issue.
First thing I would try is to run this in SQL and see what happens as it might be a data issue.
SELECT this_.Accnum as Accnum0_0_, this_.Fullname as Fullname0_0_,
this_.Add as Add0_0_, this_.State as State0_0_ FROM CustMast this_
WHERE this_.Accnum = '00059337444'
Is Accnum column defined as a string type (varchar, nvarchar etc) in your database?
Edit OK the next step is to actually confirm the SQL being sent to FoxPro. You will need to set up logging (or download a trial copy of NHProf) to find out if the SQL is correct. Your setup and code looks correct however I am not 100% sure of the choice of dialect as this may be causing you problems.
I take it you have seen this and this.
Edit2 The NHProf error seems to me that it thinks your Id should be a Int32 as it looks like it is calling at System.Data.OleDb.OleDbParameterCollection.GetParameter(Int32 index).
I think you need to add this to your mappings:-
<id name="Accnum" column="Accnum" type="string" >
Note the additional type="string"
If you use ODP.Net then you need an oracle client installed and configured, on your target machine, as well as your development machine.
The error message you post might be caused by having more than one Oracle client installed, or possibly trying to use something like a later version of odp.net with an earlier client version.

How to create an XmlMappingSource during runtime?

(Follow-Up-Question to How to change LINQ O/R-M table name/source during runtime?)
I need to change the table source of a LINQ 2 SQL O/R-Mapper table during runtime. To achieve this, I need to create an XmlMappingSource. On command line, I could use SqlMetal to create this mapping file, but I would like to create the mapping file during runtime in memory.
The XmlMappingSource is a simple xml file, looking something like this:
<?xml version="1.0" encoding="utf-8"?>
<Database Name="MyDatabase" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="dbo.MyFirstTable" Member="MyFirstTable">
<Type Name="MyFirstTable">
<Column Name="ID" Member="ID" Storage="_ID" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
<Association Name="WaStaArtArtikel_WaVerPreisanfragen" Member="WaStaArtArtikel" Storage="_WaStaArtArtikel" ThisKey="ArtikelID" OtherKey="ID" IsForeignKey="true" />
</Type>
</Table>
<Table Name="dbo.MySecondTable" Member="MySecondTable">
<Type Name="MySecondTable">
<Column Name="ID" Member="ID" Storage="_ID" DbType="UniqueIdentifier NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
<Column Name="FirstTableID" Member="FirstTableID" Storage="_FirstTableID" DbType="UniqueIdentifier NOT NULL" />
<Association Name="MySecondTable_MyFirstTable" Member="MyFirstTable" Storage="_MyFirstTable" ThisKey="FirstTableID" OtherKey="ID" IsForeignKey="true" />
</Type>
</Table>
</Database>
This should be possible to create using reflection, for example I can get the database name from a data context like this:
using System.Data.Linq.Mapping;
using System.Xml.Linq;
XDocument mapWriter = new XDocument();
DatabaseAttribute[] catx = (DatabaseAttribute[])typeof(WcfInterface.WaDataClassesDataContext).GetCustomAttributes(typeof(DatabaseAttribute), false);
XElement xDatabase = new XElement("Database");
xDatabase.Add(new XAttribute("Name", catx[0].Name));
mapWriter.Add(xDatabase);
My problem: I can't find good documentation of the mapping, so extracting the necessary information is quite error-prone - maybe someone can point me to good docs of the mapping, or, even better, to a code example how to create the mapping file?
Have you considered using LINQ to Entities, the mapping formats for LINQ to Entities are documented.
Use Damien Guard's Open Source T4 templates. They do everything SQLMetal can do and more, and you'll have the full T4 engine behind you.
I just had same problem, also I had no option to change project as its too late to do this.
I needed to update database name in mapping file in my solution.
This solution works.
My database mapping
<?xml version="1.0" encoding="utf-8"?>
<Database Name="DatabaseName" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="dbo.tblDictionary" Member="TblDictionary">
<Type Name="TblDictionary">
<Column Name="lngRecordID" Member="LngRecordID" Storage="_LngRecordID" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
<Column Name="txtWord" Member="TxtWord" Storage="_TxtWord" DbType="VarChar(50) NOT NULL" CanBeNull="false" />
</Type>
</Table>
</Database>
and finally the code:
class Program
{
static void Main(string[] args)
{
// to get embeded file name you have to add namespace of the application
const string embeddedFilename = "ConsoleApplication3.FrostOrangeMappings.xml";
// load file into stream
var embeddedStream = GetEmbeddedFile(embeddedFilename);
// process stream
ProcessStreamToXmlMappingSource(embeddedStream);
Console.ReadKey();
}
private static void ProcessStreamToXmlMappingSource(Stream stream)
{
const string newDatabaseName = "pavsDatabaseName";
var mappingFile = new XmlDocument();
mappingFile.Load(stream);
stream.Close();
// populate collection of attribues
XmlAttributeCollection collection = mappingFile.DocumentElement.Attributes;
var attribute = collection["Name"];
if(attribute==null)
{
throw new Exception("Failed to find Name attribute in xml definition");
}
// set new database name definition
collection["Name"].Value = newDatabaseName;
//display xml to user
var stringWriter = new StringWriter();
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
mappingFile.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
stringWriter.GetStringBuilder();
}
Console.WriteLine(stringWriter.ToString());
}
/// <summary>
/// Loads file into stream
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private static Stream GetEmbeddedFile(string fileName)
{
var assembly = Assembly.GetExecutingAssembly();
var stream = assembly.GetManifestResourceStream(fileName);
if (stream == null)
throw new Exception("Could not locate embedded resource '" + fileName + "' in assembly");
return stream;
}`

Categories