How to retrieve Open XML Relationships? - openxml-sdk

I'm using the Open XML SDK 2.0 to open an Excel file.
When I open the .rels file (from the .xlsx/.zip) I can see all the relationships defined.
How can I get a list of these relationships in code?

SpreadsheetDocument.Parts
and
WorkbookPart.Parts

It depends on which relationships you want. As others have mentioned use .Parts to fetch relationship information on any OpenXmlPart.
You could do it like this:
public void GetRelationships(string filepath)
{
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(filepath, false))
{
// Get relationships at spreadsheet level
IEnumerable relationships = spreadsheet.Parts;
foreach (IdPartPair partPair in relationships)
{
Console.WriteLine(partPair.RelationshipId);
Console.WriteLine(partPair.OpenXmlPart);
}
// Get relationships at workbook level
IEnumerable relationships2 = spreadsheet.WorkbookPart.Parts;
foreach (IdPartPair partPair in relationships2)
{
Console.WriteLine(partPair.RelationshipId);
Console.WriteLine(partPair.OpenXmlPart);
}
// relationships at worksheet level
IEnumerable worksheetParts = spreadsheet.WorkbookPart.WorksheetParts;
foreach (WorksheetPart worksheetPart in worksheetParts)
{
IEnumerable relationships3 = worksheetPart.Parts;
foreach (IdPartPair partPair in relationships3)
{
Console.WriteLine(partPair.RelationshipId);
Console.WriteLine(partPair.OpenXmlPart);
}
}
// Perform same concepts on any other OpenXmlPart in the package
}
}

Related

Use LINQ to Access All the Collections of a Collection on My Model?

I am trying to write a property on my model, with only a get accessor that can return a collection that is comprised of all the collections that each member of a collection property contains.
So:
Document.Lines is a collection of Line objects. Each Line has a many to many relationship with Documents called RelatedDocuments. I would like to be able to access a collection of all the RelatedDocuments from every Line in the Document. Is there a way to do that in Linq/EF?
I am trying to do this without creating a dbContext object in the model.
Long form would be something like this:
public List<RelatedDocument> RelatedDocuments
{
get
{
var RDs = new List<RelatedDocument>();
foreach (var line in Lines)
{
foreach (var rd in line.RelatedDocuments)
{
if (!RDs.Contains(rd))
{
RDs.Add(rd);
}
}
}
return RDs;
}
}
I'm not quite sure what the issue is; if Lines is IEnumerable<T> (and using System.Linq), then wouldn't something like
var allRelated = Lines
.SelectMany(line => line.RelatedDocuments)
.Distinct();
suffice?
Of course, Lines itself has to come from somewhere ..

Loading EDMX based on the condtiion

I have multiple Data Models created with the Entity framework (EDMX), and want to load based on specific conditions (similar to factory model) like so:
demoEntity obj
if(condtion1)
{
obj= new firstmodel();
}
else if
{
obj= new secondmodel();
}
Is there any way this can be done?

EF Code First, how to reflect on model

In EF code first, one specifies field properties and relationships using the fluent interface. This builds up a model. Is it possible to get a reference to this model, and reflect on it?
I want to be able to retrieve for a given field, if it is required, what its datatype is, what length, etc...
You need to access the MetadataWorkspace. The API is pretty cryptic. You may want to replace DataSpace.CSpace with DataSpace.SSpace to get the database metadata.
public class MyContext : DbContext
{
public void Test()
{
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
var mdw = objectContext.MetadataWorkspace;
var items = mdw.GetItems<EntityType>(DataSpace.CSpace);
foreach (var i in items)
{
foreach (var member in i.Members)
{
var prop = member as EdmProperty;
if (prop != null)
{
}
}
}
}

LINQ to SQL in ASP.NET MVC and Repository pattern

I'm trying to follow a tutorial from the Asp.NET MVC website which uses LINQ to Entities but I decided to use LINQ to SQL instead. I'm at the point where a new table is created called Groups which has a relationship to the Contacts table. Esentially it's a One to Many relationship where a Group can have many contacts and a Contact can only have 1 Group. Please see below the example code with CRUD operations.
I'm not sure how to implement this in LINQ to SQL. For example, how do you do this in LINQ to SQL:
return _entities.GroupSet.Include("Contacts").FirstOrDefault();
Are you supposed to do a JOIN for the two tables or is there another way?
Example CODE:
using System.Collections.Generic;
using System.Linq;
using System;
namespace ContactManager.Models
{
public class EntityContactManagerRepository : ContactManager.Models.IContactManagerRepository
{
private ContactManagerDBEntities _entities = new ContactManagerDBEntities();
// Contact methods
public Contact GetContact(int id)
{
return (from c in _entities.ContactSet.Include("Group")
where c.Id == id
select c).FirstOrDefault();
}
public Contact CreateContact(int groupId, Contact contactToCreate)
{
// Associate group with contact
contactToCreate.Group = GetGroup(groupId);
// Save new contact
_entities.AddToContactSet(contactToCreate);
_entities.SaveChanges();
return contactToCreate;
}
public Contact EditContact(int groupId, Contact contactToEdit)
{
// Get original contact
var originalContact = GetContact(contactToEdit.Id);
// Update with new group
originalContact.Group = GetGroup(groupId);
// Save changes
_entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit);
_entities.SaveChanges();
return contactToEdit;
}
public void DeleteContact(Contact contactToDelete)
{
var originalContact = GetContact(contactToDelete.Id);
_entities.DeleteObject(originalContact);
_entities.SaveChanges();
}
public Group CreateGroup(Group groupToCreate)
{
_entities.AddToGroupSet(groupToCreate);
_entities.SaveChanges();
return groupToCreate;
}
// Group Methods
public IEnumerable<Group> ListGroups()
{
return _entities.GroupSet.ToList();
}
public Group GetFirstGroup()
{
return _entities.GroupSet.Include("Contacts").FirstOrDefault();
}
public Group GetGroup(int id)
{
return (from g in _entities.GroupSet.Include("Contacts")
where g.Id == id
select g).FirstOrDefault();
}
public void DeleteGroup(Group groupToDelete)
{
var originalGroup = GetGroup(groupToDelete.Id);
_entities.DeleteObject(originalGroup);
_entities.SaveChanges();
}
}
}
You need to specify some DataLoadOptions to create the join for you:
So to do this, you have to create a DataContext for each type of query with the correct DataLoadOptions:
var db = new WhateverDbDataContext();
DataLoadOptions options = new DataLoadOptions();
db.LoadOptions = options;
options.LoadWith(x => x.Contacts);
return db.SomeTable.FirstorDefault();
Linq to sql does not support the Include method. If you don't care if the relationship is lazy loaded, then you don't have to do anything. If you want it to be eager loaded, then you have use the more convoluted DataLoadOptions.
See this article:
http://blog.stevensanderson.com/2007/12/02/linq-to-sql-lazy-and-eager-loading-hiccups/

WP7 Insert all linq results in an ObservableCollection

I parse an xml results from a webservice using linq :
XElement items = XElement.Parse(e.Result);
MyListBox.ItemsSource = from item in items.Descendants("node")
select new MyViewModel
{
...
};
This automatically populate my ListBox. But the problem is, I usually access my ObservableCollection like this :
App.MyViewModel.MyItems;
having in my xaml :
ItemsSource="{Binding MyItems,}"
How can I modify directly my ObservableCollection ? I read Cast LINQ result to ObservableCollection
and tried this :
var v = from item in items.Descendants("node")
select new MyViewModel
{
...
};
OApp.MyViewModel.MyItems = new ObservableCollection<MyViewModel>(v);
But I can't since this in WP7 (Silverlight 3), and there is no constructor like this
Thanks !
I'd just invent a static method like this:-
public static ObservableCollection<T> CreateObservableCollect<T>(IEnumerable<T> range)
{
var result = new ObservableCollection<T>();
foreach (T item in range)
{
result.Add(item);
}
return result;
}
Now your last line of code becomes:-
OApp.MyViewModel.MyItems = new CreateObservableCollection<MyViewModel>(v);
The constructor you're trying to use is in Silverlight, just not available on the phone. (as per MSDN)
Unfortunately, you'll have to populate your ObservableCollection yourself.
Do you need ObservableCollection? Do you need add or delete objects from collection or just update?
If only update, you can change MyViewModel.MyItems to:
public MyTypeOfCollection MyItems
{
get { return _myItems; }
set
{
_myItems = value;
OnNotifyPropertyChanged("MyItems");//invoke INotifyPropertyChanged.PropertyChanged
}
}
If you need adding or deleting of items, you can extend your collection to:
public static class Extend
{
// Extend ObservableCollection<T> Class
public static void AddRange(this System.Collections.ObjectModel.ObservableCollection o, T[] items)
{
foreach (var item in items)
{
o.Add(item);
}
}
}

Resources