Calling child constructor by casting (ChildClass)parentObject; to track revisions - c#

To track revisions of a Page class, I have a PageRevision class which inherits from Page and adds a revision ID (Guid RevisionID;).
If possible, how should I cast an existing Page object to a PageRevision and ensure that the PageRevision constructor is called to create a new revision ID?
I could could have a PageRevision(Page page) constructor which generates the Guid and copies all the Page attributes, but I want to automate it, especially if a Page class has many attributes (and I later add one, and forget to modify the copy constructor).
Desired use
Page page = new Page(123, "Page Title", "Page Body"); // where 123 is page ID
PageRevision revision = (PageRevision)page;
// now revision.RevisionID should be a new Guid.
Page, PageRevision classes:
public class Page
{
public int ID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
}
public class PageRevision : Page
{
public Guid RevisionID { get; set; }
public PageRevision()
{
this.RevisionID = Guid.NewGuid();
}
}
Edit based on feedback:
Besides the now-obvious (Horse)Animal; casting problem, Jon Skeet recommends a composite revision:
public class PageRevision : Page
{
private readonly Page page;
private readonly Guid id;
public Guid RevisionID { get { return id; } }
public Page Page { get { return page; } }
public PageRevision(Page page)
{
this.id = Guid.NewGuid();
this.page = page;
}
}
However, this is quite different from my data model and I'd like to keep the two as similar as possible. In my database, the PageRevisions table has the same columns as the Pages table, expect for an extra RevisionID column. This is easy to version with a database trigger.
In the light of this composite approach, would it make more sense to have a PageRevisions to store all page data: a RevisionID, Title and Body, while a Pages table only stores an URL Slug and a RevisionID that refers to the PageRevisions table?

Why not make your PageRevision class compose instead of inheriting?
public class PageRevision : Page
{
private readonly Page page;
private readonly Guid id;
public Guid RevisionID { get { return id; } }
public Page Page { get { return page; } }
public PageRevision(Page page)
{
this.id = Guid.NewGuid();
this.page = page;
}
}

You cannot.
A horse is an animal, but not every animal is a horse.
So horse => animal is possible, but animal => horse not. And you are trying to cast your animal into a horse.

The PageRevision constructor ALWAYS gets called regardless if you cast the class to PageRevision or not. So this isn't going to work at all.
It likely makes more sense you tell why you want to do that because you are likely doing that for reasons that are solved in other ways.

During a cast, there is no constructor called, because the object is already created.
Although your cast will fail at runtime, cause Page cannot be cast to PageRevision (the other way is possible)
In your case i would add the RevisionId to your base class Page. If you create a Page object it could be created with Guid.Empty. Derived classes could set the RevisionId using an constructor of your base class Page.
public class Page {
public Page() {
RevisionId = Guid.Empty;
}
protected Page(Guid revisionId) {
RevisionId = revisionId;
}
public Guid RevisionId {
get;
private set;
}
}
public class PageRevision : Page {
public PageRevision()
: base(Guid.NewGuid()) {
}
}

Related

Get specific type from derived class

Brief: I'm creating an MVC application in which I need to display a variety of types documents, some containing more author information than others.
What I wanna do: My approach is to have a generic "view document" view, which dynamically displays the document in a format dictated by the shape/type of the object passed to it.
Example: A simple document would be loaded into a SimpleDocumentViewModel, and display as such. However I'd like to load a larger type of document into an ExtendedDocumentViewModel, bringing with it additional information about both the document and the author. The view(s) would then display the appropriate data based on the object it receives.
Where I'm at now: In this vein I've created the following interfaces and classes, but I'm stuck as to how to return/identify the more specific return types in their derived classes.
abstract class BaseDocumentViewModel : DocumentViewModel, IDocumentViewModel
{
public int DocumentId { get; set; }
public string Body { get; set; }
public IAuthorViewModel Author { get; set; }
}
class SimpleDocumentViewModel : BaseDocumentViewModel
{
}
class ExtendedDocumentViewModel : BaseDocumentViewModel
{
public new IAuthorExtendedViewModel Author { get; set; }
}
interface IAuthorViewModel
{
int PersonId { get; set; }
string Name { get; set; }
}
interface IAuthorExtendedViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
}
Question: So my question is; how best can I get the specific types from the fully implemented classes, or do I need to return the base types and query it all in the view? Or am I off my head and need to go back to the drawing board?
Edits:
I know that c# doesn't support return type covarience, but hoped that there may be another way of returning/identifying the derived types so that I don't have to query them all in the view.
My current solution would be to always return the base types, and have a separate view for each concrete type that simply casts each object to the correct type, only querying those that could differ. Perhaps this is the best solution end of, but it feels very inelegant.
Usually you can do a simple "is" check. So you can have conditional rendering in your views, for example:
#if(Model is ExtendedDocumentViewModel)
{
// render ExtendedDocumentViewModel html here
}
Type checking is usually considered an anti pattern, however I am not sure if there is a much better approach to this problem. If you are using .NET Core you can also check the subclass tag here http://examples.aspnetcore.mvc-controls.com/InputExamples/SubClass .
Possible cleaner option is to just have a signature in the interface called GetView that each document has to implement. This way each document type has their own way of implementing the function and the calling function knows that each document has a function GetView. This method will work well if every document has a unique way of viewing the document. However if some documents share the same way of getting views, then may I suggest creating each View type into their own class and you can assign the views types to each document. I suggest looking into the strategy pattern.
First suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
view GetView()
{
... do document specific stuff
... return view
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
view GetView()
{
... do document specific stuff
... return view
}
}
interface IAuthorViewModel
{
view GetView();
}
Second suggestion:
class SimpleDocumentViewModel : IAuthorViewModel
{
public viewType1 view {get;set;}
public SimpleDocumentViewModel(viewType1 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView();
}
}
class ExtendedDocumentViewModel : IAuthorViewModel
{
int ExtraData { get; set; }
int MoreExtraData { get; set; }
public viewType2 view {get;set;}
public ExtendedDocumentViewModel(viewType2 viewIn,etc...)
{
view = viewIn;
}
view GetView()
{
return view.GetView(ExtraData,MoreExtraData);
}
}
interface IAuthorViewModel
{
view GetView();
}
I may be way off base here, but as I understand your question... why not just throw the return types in an object and pass that to your view?
You could look at the desired method and use reflection to pull out whatever info you want. Modify this and the object class hold whatever you want it to.
public class DiscoverInternalClass
{
public List<InternalClassObject> FindClassMethods(Type type)
{
List<InternalClassObject> MethodList = new List<InternalClassObject>();
MethodInfo[] methodInfo = type.GetMethods();
foreach (MethodInfo m in methodInfo)
{
List<string> propTypeList = new List<string>();
List<string> propNameList = new List<string>();
string returntype = m.ReturnType.ToString();
foreach (var x in m.GetParameters())
{
propTypeList.Add(x.ParameterType.Name);
propNameList.Add(x.Name);
}
InternalClassObject ICO = new InternalClassObject(c.Name, propNameList, propTypeList);
MethodList.Add(ICO);
}
return MethodList;
}
}
he object class could be something like this or modify it however you want:
public class InternalClassObject
{
public string Name { get; set; }
public List<string> ParameterNameList { get; set; }
public List<string> ParameterList { get; set; }
public InternalClassObject(string iName,List<string> iParameterNameList, List<string> iParameterList)
{
Name = iName;
ParameterNameList = iParameterNameList;
ParameterList = iParameterList;
}
}
You could call the method like this with the desired class.
public static List<InternalClassObject> MethodList = new List<InternalClassObject>();
DiscoverInternalClass newDiscover= new DiscoverInternalClass();
MethodList = newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
Now you can have your GetView build based on what is in MethodList
Hope this helps!

Why is construction taking a lot of time?

I have classes that I use with EntityFramework:
public partial class BaseDocument
{
public BaseDocument()
{
DocumentLinks = new List<DocumentLink>();
}
public int Id {set;get;}
public virtual List<DocumentLink> DocumentLinks {set;get;}
}
public partial class Payment:BaseDocument
{
}
public partial class Bill:BaseDocument
{
}
public partial class DocumentLink
{
public int Id{set;get;}
public int StartDocId{set;get;}
public int EndDocId{set;get;}
public virtual BaseDocument StartDoc{set;get;}
public virtual BaseDocument EndDoc{set;get;}
}
Now I select document with Linq and want to iterate through list of his DocumentLinks.
var payment = dbContext.Payments.First(t=>t.Id = id);
foreach(var link in payment.DocumentLinks)
{
if (link is Payment)
{
//do something
}
else if (link is Bill)
{
//do something
}
}
And my code works very slowly at the line if (link is Payment). After this line everything works quickly.
What is wrong?
You mean it is slow in the line that is actually executing the database query? Hint - this is why it is slow.
var payment = dbContext.Payments.First(t=>t.Id = id);
I fail to see how the payment includes the DocumentLiks - which means they are lazy loaded. Which means this happens in the foreach. And there you go. Slow.
Include them in the initial query.
Not a direct answer to your question, but a suggestion that you shouldn't type-sniff like this. Polymorphism allows you to ignore the exact type of an object, use it.
Put whatever behavior you need into BaseDocument and remove the is Payment and is Bill:
var payment = dbContext.Payments[id];
foreach(var link in payment.DocumentLiks)
{
link.DoSomething();
}
This may be because of Lazy loading.
In your DBContext configuration specify:
this.Configuration.LazyLoadingEnabled = false;

Overriding inner/subclass fields

I currently have a 'Customer' class that looks like:
public class Customer
{
public string email { get; set; }
public string first_name { get; set; }
public string middle_name { get; set; }
public string last_name { get; set; }
}
However, I also have another class that wraps the 'Customer' as part of a REST 'GET' request:
public class CustomerRequest
{
Customer customer;
}
In my CustomerRequest, I'd like to make the email field required. In other words, I'd like to override the default behavior of the Customer class to throw an ArgumentNullException if the email isn't entered upon object creation. I'd only like to enforce this requirement as part of the CustomerRequest, NOT the customer.
I've tried to make the underlying Customer class fields 'virtual', but this still doesn't allow me to override them in the CustomerRequest class.
How can I achieve my desired functionality?
For whatever it's worth, I'd rethink throwing exceptions in a constructor. Doing so causes the exception to be caught and rethrown as an ObjectInitializationException by the runtime--an operation completely outside your control. These exceptions can be obscure and difficult to pin down, especially to developers who aren't familiar with the object model.
What you might do instead is put a Validate method on the CustomerRequest object that verifies that all required fields are populated (in this case, the email address). Sure, it requires a manual method invocation, but it's explicit, and it doesn't unexpectedly surprise you at runtime.
Short answer: you can't change the behaviour of Customer just because it's a field in another class.
Longer answer: there are a couple of ways of achieving what you're looking for. #MetroSmurf's answer is probably the simplest, but you could also change the customer field on CustomerRequest to be a property and perform the check there i.e.
public class CustomerRequest
{
private Customer _customer;
public Customer Customer
{
get { return _customer; }
set
{
if (string.IsNullOrEmpty(value.email))
{
throw new ArgumentNullException("email");
}
_cutomer = value;
}
}
}
But honestly, you'd just be better off validating the CustomerRequest when you recieve it.
public CustomerRequest
{
public Customer customer {get;set;}
public CustomerRequest(Customer c)
{
this.customer = CheckEmail(c);
}
private Customer CheckEmail(Customer c)
{
if (c.email == null) throw ArgumentNullException;
return c;
}
}

EntityFramework CodeFirst Instantiate Collection

I have an EntityFramework object with a collection, for instance:
public class User
{
public virtual ICollection<Page> Pages { get; set; }
}
What is the best practice - leaving it like this or instantiating the collection in the constructor (or something else?) If I instantiate the collection into a default blank list like this:
public class User
{
public virtual ICollection<Page> Pages { get; set; }
public User()
{
Pages = new List<Page>();
}
}
Then I get a DevExpress/Code Analysis warning about instantiating virtual properties in the constructor - is there any danger to doing it this way?
this would be a better decision:
private readonly IList<Page> _page;
public User(IEnumerable<Page> page)
{
_page = new List<Page>(page);
}
public IList<Page> Page
{
get { return _page; }
}
be careful about using about ICollection<>, IEumerable<> and IList<>, see more info here
Do not instantiate it, leave your POCO object as it is and let EF operates on it as expected. EF will instantiate them for you. You should know that EF will fill the navigation property which is marked by virtual through dynamic proxy.

Orchard Project Module getting error: No persister for: SomePartRecord

I am trying to create a simple setting in Orchard that appears in the settings page. I have created a module which is adding my ContentPart to the settings page and is correctly creating a table in the database but every time the cshtml file is rendered and the property of the record is accessed I keep getting the following NHibernate Record.
No persister for: TekFlow.Contact.TekFlowEmailSettingsPartRecord.
(TekFlow.Contact is the Module name)
Below is all of the code that I am using to create the Record/Part/Handler/Driver needed in Orchard.
public class TekFlowEmailSettingsPartDriver : ContentPartDriver<TekFlowEmailSettingsPart>
{
public TekFlowEmailSettingsPartDriver()
{
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override DriverResult Editor(TekFlowEmailSettingsPart part, dynamic shapeHelper)
{
return ContentShape("Parts_TekFlowEmailSettings_Edit",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.TekFlowEmailSettings", Model: part, Prefix: Prefix)
);
}
protected override DriverResult Editor(TekFlowEmailSettingsPart part, Orchard.ContentManagement.IUpdateModel updater, dynamic shapeHelper)
{
bool success = updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
[UsedImplicitly]
public class TekFlowEmailSettingsPartHandler : ContentHandler
{
public TekFlowEmailSettingsPartHandler(IRepository<TekFlowEmailSettingsPartRecord> repository)
{
Filters.Add(new ActivatingFilter<TekFlowEmailSettingsPart>("Site"));
Filters.Add(StorageFilter.For(repository));
}
}
public class TekFlowEmailSettingsPartRecord : ContentPartRecord {
public virtual string SendToEmail { get; set; }
}
public class TekFlowEmailSettingsPart : ContentPart<TekFlowEmailSettingsPartRecord>
{
public string SendToEmail
{
get { return Record.SendToEmail; }
set { Record.SendToEmail = value; }
}
}
public class TekFlowEmailSettingsDataMigration : DataMigrationImpl
{
public int Create()
{
SchemaBuilder.CreateTable("TekFlowEmailSettingsPartRecord",
table => table
.ContentPartRecord()
.Column<string>("SendToEmail", c => c.WithDefault("SomeEmail#somedomain.com").WithLength(255))
);
ContentDefinitionManager.AlterPartDefinition(
typeof(TekFlowEmailSettingsPart).Name, cfg => cfg.Attachable());
return 1;
}
}
Turns out that if your Part and Record are not in your "Models" namespace that this wont work in orchard. When I changed the Namespace for the two classes it worked. Must be an assumption that Orchard is making.
I got the same error from not having virtual variables in my record.
(In my case it did not inherit ContentPartRecord and declared it's own Id, not sure if the issue simply was that Id was not virtual or that all variables had to be virtual.)
Also as mentioned above your namespace must end with Models or Records, as explained here:
https://orchard.codeplex.com/discussions/267968
My Favicon module has pretty much the same structure and when I did a file by file comparison I could not find a significant difference. The only thing that looks suspicious is that you didn't define a prefix in your driver. That may interfere with the binder's ability to rehydrate the model but I'm not sure how that would affect persistence.

Categories

Resources