I'm trying to use xaml to instantiate a set of objects as follows:
<Application.Resources>
<local:RelationshipDefinition x:Key="R1" Name="College"
Type="One2one" ForwardName="Attended"
/>
<local:RelationshipDefinition x:Key="R2" Name="HasPart"
Type="One2manyBi" ForwardName="Part" BackwardName="PartOf"
/>
<local:RelationshipDefinition x:Key="R3" Name="HasChild"
Type="One2manyBi" ForwardName="Child" BackwardName="Parent"
/>
</Application.Resources>
The first instance "R1" works, and is instantiated. The other two aren't, even though no errors are thrown. Whichever of the relationships I move into the first place works correctly, so it's clear that it will only "accept" one instance. Is there a way for me to do this? I've experimented with trying to create a Collection class to hold them, but haven't succeeded. Trying to designate the collection as a ContentProperty like this:
[ContentProperty("Definitions")]
produces this error:
Error CS1729 'ContentPropertyAttribute' does not contain a constructor that takes 1 arguments
I'm new to the ways of xaml, and imagine there must be some fairly easy way to accomplish this.
After my initial post I found that if I created a separate ResourceDictionary to hold each RelationshipDefinition and included each separately like this:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="HasChildrenRelationship.xaml"/>
<ResourceDictionary Source="CollegeRelationship.xaml"/>
<ResourceDictionary Source="HasPartRelationship.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
The RelationshipDefinition object is a simple declarative object that is used by a semantic net based data access method. Each user 'declares' the network relationships they well be using in their particular case. Here's a fragment of the code from the class. It's essentially all Dependency Properties with a constructor that registers/finds the RelationshipDefinition in a global store.
public class RelationshipDefinition : DependencyObject
{
public string UID { get; set; } = Guid.NewGuid().ToString();
public string Name
{
get { return (string)GetValue(NameProperty); }
set
{
SetValue(NameProperty, value);
RegisterRelationshipDefinition(this);
}
}
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(RelationshipDefinition), new PropertyMetadata(null));
public RelationshipType Type
{
get { return (RelationshipType)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(RelationshipType), typeof(RelationshipDefinition), new PropertyMetadata(null));
...etc...
It's used like this:
Person chris = new Person(){ FirstName = "Chris", LastName = "Smith", Age = 19 };
Person annemarie = new Person() {FirstName = "Anne-Marie", LastName = "Smith", Age = 22 };
Person john = new Person() { FirstName = "John", LastName = "Smith", Age = 47};
SNet.Link(from: chris, to: nyu, via: "College");
SNet.Link(from: john, to: chris, via: "HasChild");
SNet.Link(from: john, to: annemarie, via: "HasChild");
Person p1 = SNet.GetBackLink<Person>(from: annemarie, via: "HasChild");
List<Person> children = SNet.GetForwardLinks<Person>(from: john, via: "HasChild");
All the RelationshipDefinition objects were instantiated correctly. I'm sure there must be a way to include them together that I'm missing.
Related
I've got an NHibernate 4 project with several collection relationships. I'm unit-testing the object model, exercising all the collections. Most work fine, but in one case, the child collection is cascade-saved properly, but on loading the parent entity and examining the collection property, the child collection is empty.
Here are the abbreviated classes. GatewayUser is the parent object, and it has a collection of Student. The collection has a private backing property, and AddStudent/RemoveStudent methods.
Further complications: I'm using the NHibernate.AspNet.Identity library for OAuth2 user management, and GatewayUser inherits from IdentityUser. That in turn inherits from the the library's internal base entity class, which is different from my project's own base class.
public class GatewayUser : IdentityUser
{
public GatewayUser()
{
}
public virtual string FirstName { get; set; }
// ...More value properties and OAuth stuff omitted
// students associated with this user
private IList<Student> _students = new List<Student>();
public virtual IList<Student> Students
{
get { return new ReadOnlyCollection<Student>(_students); }
}
public virtual GatewayUser AddStudent(Student s)
{
if (_students.Contains(s))
return this;
s.GatewayUser = this;
_students.Add(s);
return this;
}
public virtual GatewayUser RemoveStudent(Student s)
{
if (_students.Contains(s))
{
_students.Remove(s);
}
return this;
}
Student is more ordinary; it inherits from my own BaseEntity class, has many value properties, and its own child collection of ProgramApplication items. Interestingly, this collection saves and loads fine; it's got the same structure (private backer, etc.) as the failing collection in GatewayUser.
The mapping is complicated, because the library internally maps its classes with NHiberante.Mapping.ByCode.Conformist classes (which I have no prior experience with).
I'm mapping my own classes with NHibernate automapping, because I have so many classes and properties to map. To get it all working, I copied the library's mapping helper class, and modified it a bit to add my base entity classes to it's list called baseEntityToIgnore. I also had to create a conformist mapping for GatewayUser, since it has a different base entity type, and my automapping wouldn't pick it up.
The unit test looks like this:
[Test]
public void GatewayUserCascadesStudents()
{
var u = new GatewayUser() { FirstName = "Mama", LastName = "Bear", UserName = "somebody#example.com" };
var s1 = new Student() { FirstName = "First", LastName = "Student" };
var s2 = new Student() { FirstName = "Second", LastName = "Student" };
u.AddStudent(s1).AddStudent(s2);
using (var s = NewSession())
using (var tx = s.BeginTransaction())
{
s.Save(u);
tx.Commit();
}
GatewayUser fetched = null;
int count = 0;
using (var s = NewSession())
{
fetched = s.Get<GatewayUser>(u.Id);
count = fetched.Students.Count;
}
Assert.AreEqual(2, count);
}
The generated SQL inserts into both AspNetUsers and GatewayUser (reflecting the inheritance relationship), and inserts two records into Student. All good. On fetching, the SELECT joins the two user tables, and I get a GatewayUser object, but accessing the Students collection does not trigger a SELECT on the Student table. But if I change the mapping to Lazy(CollectionLazy.NoLazy), the SQL to select eagerly load Students appears in the log, but the collection is not populated. If I switch the database from SQLite to Sql Server, I see the student records in the table. The generated SQL (when NoLazy is applied) will fetch them. So on the database end, things look fine.
I have to think my Frankenstein mapping situation is to blame. I'm mixing the library's conformist mapping with Fluent mapping, and there are two different base entity classes. However, the generated schema looks correct, and the save cascades correctly, so I don't know if that's the issue.
Found my own answer. My mapping of the parent class's list was like this:
public class GatewayUserMap : JoinedSubclassMapping
{
public GatewayUserMap()
{
Key(g => g.Column("Id"));
Property(c => c.FirstName, m => m.Length(50));
// ... more properties
List(gu => gu.Students, map =>
{
map.Key(c => c.Column("GatewayUser_Id"));
map.Cascade(Cascade.All | Cascade.DeleteOrphans);
map.Index(li => li.Column("ListIndex"));
map.Access(Accessor.Field | Accessor.NoSetter);
}
);
}
}
I have a private backing field for the collection. Removing Accessor.NoSetter from the collection mapping fixed it. In fact, it still worked without Accessor.Field -- I guess the mapper does a good job of looking around for one, and using it if found. Changing the name of the private backer from "_students" to "funnyName" prevented the mapper from finding it.
I've been making use of binding to sample data so that I can get a feel of what the app is going to look like during runtime.
Things have been going great until I had to bind to a List<>. I made a sample application to demonstrate the problem.
Person.cs
public string FullName { get; set; }
public int Age { get; set; }
public string Sex { get; set; }
public List<string> Friends { get; set; }
MainViewModelSampleData.xaml
<vm:MainViewModel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:StackoverflowQuestion.ViewModels">
<vm:MainViewModel.Items>
<vm:Person FullName="Homer Simpson" Age="45" Sex="Male" />
<vm:Person FullName="Bruce Wayne" Age="32" Sex="Male" Friends="" />
</vm:MainViewModel.Items>
I can get the design view to correctly shows the string FullName, int Age, and string Sex.
What I don't know and can't figure out is how to bind data from List<string> Friends so that I can view it on the design view.
The solution is 'extracting' the Friends value
<vm:Person FullName="Bruce Wayne" Age="32" Sex="Male">
<vm:Person.Friends>
<x:String>First</x:String>
<x:String>Second</x:String>
</vm:Person.Friends>
Depending on the version of App x:String is necessary or the literal directly
<vm:Person FullName="Bruce Wayne" Age="32" Sex="Male">
<vm:Person.Friends>
First
Second
</vm:Person.Friends>
And the last option is add the following namespace
xmlns:System="clr-namespace:System;assembly=mscorlib"
<phone:PhoneApplicationPage.DataContext>
<local:Person Name="ww">
<local:Person.Friends>
<System:String>one</System:String>
<System:String>one</System:String>
</local:Person.Friends>
</local:Person>
I'm trying to deserialize two types of json:
{
name: "bob",
worksAt: {
name: "Bobs department store",
location: "downtown"
},
age: 46
}
and
{
name: "Tom",
worksAt: "company:Bobs department store",
age: 27
}
into these objects:
The first way creates two new objects, the second way requests the object from the database based on the contents of a string.
sort of like how jackson mapper can deserialize an arbitrary string into an object, for objects like this:
public class Company{
public String name;
public Employee[] employees
public Company(){}
public Company(String json){
//turn string into object using whatever encoding you want blah blah blah...
}
}
The trouble is I need both. I need it to handle objects and strings. Both could arrive from the same input.
The first think I tried was making a Converter
It says these create a delegate type to pass to the deserializer, but the converter is always applied even when the datatype isn't a string. So that didn't work.
I've also tried a normal deserializer, but I can't find a way to defer to the BeanDeserializer. The beanDeserializer is so complicated that I can't manually instantiate it. I also see no way to defer to a default deserializer in jackson mapper.
Do I have to re-implement jackson mappers deserialization to do this? Is there any way for a deserializer to say "I can't do this, use the default implementation."?
Edit: Some further progress. Based on the Jackson Mapper source code, it looks like you can instatiate bean deserializers like this:
DeserializationConfig config = ctxt.getConfig();
JavaType type = config.constructType(_valueClass);
BeanDescription introspect = config.introspect(type);
JsonDeserializer<Object> beanDeserializer = ctxt.getFactory().createBeanDeserializer(ctxt, type , introspect);
but for some reason all the _beanProperties have the FailingDeserializer set for their _valueDeserializer and the whole thing fails. So I have no idea why that happens...
Have you tried writing a custom deserializer? This gives you the most control on how Jackson deserializes the object. You may be able to try to deserialize one way, and if there's an error, try another way.
Jackson can also handle polymorphic deserialization, though this would require a small change to the json to include type information, and it sounds like your problem constraints might not allow that.
If I understand the problem correctly, I would recommend using JsonNode. You can define a setter in your top-level type like this:
setWorksAt(JsonNode node) {
if (node.getNodeType == JsonNodeType.STRING) {
String name = node.getText();
name = name.substring(name.lastIndexOf(':'));
this.company = new Company(name);
} else if (node.getNodeType == JsonNodeType.OBJECT) {
this.company = mapper.treeToValue(node, Company.class);
}
}
That allows you to handle the two separate worksFor inputs, while still allowing the standard mapper to handle any substructures for the OBJECT case.
With recent versions of Jackson (2.8+ I think, definitely works with 2.9) you can use multiple #JsonCreator and do something like this:
public class Company {
private String name;
private String location;
private Company(String name, String location) {
this.name = name;
this.location = location;
}
private Company(String stringRepresentation) {
// add code here to parse string and extract name and location
}
#JsonCreator
private static Company fromJson(
#JsonProperty("name") String name,
#JsonProperty("location") String location)
{
return new Company(name, location);
}
#JsonCreator
private static Company fromJson(String str) {
return Company(str);
}
}
My system currently runs in differents environments.
I got a Environment enum on my system, something like this
public enum Environment {
[UsePayPal(false)]
[ServerInstallDir("InstallPathOnServer")]
[IntegrationSystemURI("localhost/someFakeURI")]
[UpdateSomeInfo(true)]
[QueuePrefix("DEV")]
[UseCache(false)]
[AnotherSystemURI("localhost/anotherFakeURI")]
Development = 0,
[UsePayPal(false)]
[ServerInstallDir("InstallPathOnBUILDServer")]
[IntegrationSystemURI("build-server/someFakeURI")]
[UpdateSomeInfo(true)]
[QueuePrefix("QA")]
[UseCache(false)]
[AnotherSystemURI("build-server/anotherFakeURI")]
QA = 1,
[UsePayPal(true)]
[ServerInstallDir("InstallPathOnServer")]
[IntegrationSystemURI("someservice.com/URI")]
[UpdateSomeInfo(true)]
[QueuePrefix("PRD")]
[UseCache(true)]
[AnotherSystemURI("anotherservice/URI")]
Production = 2,
}
I'm working like this, because I dont like code like
if(CURRENT_ENVIRONMENT == Environment.QA || CURRENT_ENVIRONMENT == Environment.DEV)
EnableCache()
or
if(CURRENT_ENVIRONMENT == Environment.QA || CURRENT_ENVIRONMENT == Environment.DEV){
DoSomeStuff();
}
because I think that's scatter my logic all over the system, and not on a single point.
If some day I add another Test Enviroment, I dont need to go all over my code to see if I work like on Development, QA or Production enviroment.
Ok, but, with all that config I may end up with too maby attributes on my Enum, lets say, in 3 years each enum value will have 15~20 attributes, and that looks weird.
What do you guys think? How do you usually handle this situation? Its really too many attributes, or thats ok?
Create an Environment class with a private constructor and as many properties as you need to describe the environment, and expose static readonly instances as public properties. You can also have an Environment.Current property that points to one of these instances.
Example code:
sealed class Environment
{
// The current environment is going to be one of these -- 1:1 mapping to enum values
// You might also make these properties if there's fine print pointing towards that
public static readonly Environment TestEnvironment;
public static readonly Environment ProductionEnvironment;
// Access the environment through this
public static Environment Current { get; set; }
static Environment()
{
TestEnvironment = new Environment {
UsePayPal = false,
ServerInstallDir = "/test"
};
ProductionEnvironment = new Environment {
UsePayPal = true,
ServerInstallDir = "/prod"
};
}
// Environment propeties here:
public bool UsePayPal { get; private set; }
public string ServerInstallDir { get; private set; }
// We don't want anyone to create "unauthorized" instances of Environment
private Environment() {}
}
Use it like:
Environment.Current = Environment.TestEnvironment;
// later on...
Console.WriteLine(Environment.Current.ServerInstallDir);
Please forgive, I'm new to Silverlight and am still trying to wrap my head around data binding...
I have a generic list obtained from a class using LINQ. The list has 4 objects, each object consisting of a Letter property (string - A, B, C and D) and a corresponding Number property (integer - 1, 2, 3, and 4).
In Silverlight, I have a combobox control and a text block. I'm trying to figure out how to:
Bind the combobox to the generic list so that the letters populate the combobox
When the user selects a letter in the combobox (say C), the corresponding integer value (3 for this example) is displayed in the text block.
I'm been trying to make it work with ItemsSource, but am not getting anywhere. Any advice? I'm working in VB, by the way...
Thanks
I did something similar with a Label and a radComboBox (from Telerik).
If you want to do this by code, you'll have to do it like this:
'This code is untested but at least it shows the logic
'Step #1, filling the combobox
yourComboBox.ItemsSource = yourList
yourComboBox.SelectedValuePath = "IntegerPropertyName"
yourComboBox.DisplayMemberPath = "StringPropertyName"
'Step #2, binding the TextBlock
Dim binding As System.Windows.Data.Binding = Nothing
binding = New System.Windows.Data.Binding()
binding.Source = yourComboBox
binding.Mode = Data.BindingMode.TwoWay 'Maybe in your case you'll want OneWay
binding.Path = New System.Windows.PropertyPath("SelectedItem.IntegerPropertyName")
youtTextBlock.SetBinding(TextBlock.TextProperty, binding)
... and if you want to do it directly in the XAML, have a look at this post for step #2
I would do this in XAML only. Here is my (Sample) Code:
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding ElementName=MyComboBox, Path=SelectedValue}" VerticalAlignment="Top"/>
<ComboBox
x:Name="MyComboBox"
ItemsSource="{Binding MyColl}"
Height="22"
SelectedValuePath="I"
DisplayMemberPath="C"/>
</Grid>
And here is my Code behind: (EDIT: sry for the c# code)
public class MyClass
{
public int I { get; set; }
public string C { get; set; }
}
public partial class MainPage : UserControl
{
public ObservableCollection<MyClass> MyColl { get; set; }
public MainPage()
{
MyColl = new ObservableCollection<MyClass>();
MyColl.Add(new MyClass{ C = "A", I = 1});
MyColl.Add(new MyClass { C = "B", I = 2 });
MyColl.Add(new MyClass { C = "C", I = 3 });
MyColl.Add(new MyClass { C = "D", I = 4 });
DataContext = this;
InitializeComponent();
}
}
Remember: This is just a sample code. I strongly recommend you to hav a look at MVVM (http://jesseliberty.com/2010/05/08/mvvm-its-not-kool-aid-3/). A better Solution would be, to bind the SelectedItem (or the selected value) to your ViewModel, and then reference this value in the TextBlock.
BR,
TJ