I have a class that I loaded using Objectify v5, how do I get the associated Key<T> from Objectify?
#Entity
#Cache
public abstract class BaseEntity<T,P>
{
#Parent
private Key<P> parent;
#Id
private String uuid;
}
I know that ofy().save() returns the Key<T> but I want to get the Key<T> from an Entity that was loaded by a filter or id.
I have searched all over the Objectify v5 documentation and can't find methods that take an Entity and return a Key<T> of that Entity.
Solution
Key.create(T pojo);
But in the case above it doesn't work from inside my BaseEntity<T,P> class.
#Nonnull
public Key<T> getKey() { return Key.create(this); }
Complains that it wants to cast the result to Key<T>.
After some experimenting I just added a method to my BaseEntity
#Nonnull
public Key<T> getKey()
{
return Key.create(this.parent, this.entityType, this.uuid.toString());
}
This returns the same Key<T> that is auto-generated.
Java's typing system is not sophisticated enough to express "i want this to be whatever type 'this' happens to be at the leaf level" (since you are in an abstract class). Scala could do this, but not Java. At least not to my knowledge.
Unless I'm misunderstanding what you are trying to do...?
Related
So, I have changed my application so that I may use an integer primary key on my tables (a horrid process by the way). Everything works fine. Consider my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>, IIDentityContext
{
public ApplicationDbContext()
: base("OwinTestDefault")
{
Database.SetInitializer<ApplicationDbContext>(null);
}
...
}
Now consider, for example, my user login class here, in its entirety:
public class CustomUserLogin : IdentityUserLogin<int>
{
}
It seemed silly to have to make a class just for this, and that I should be able to just replace any instance of this with IdentityuserLogin<int> in the code, resulting in this now:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, IdentityUserLogin<int>, CustomUserRole, CustomUserClaim>, IIDentityContext
{
public ApplicationDbContext()
: base("OwinTestDefault")
{
Database.SetInitializer<ApplicationDbContext>(null);
}
...
}
However, bafflingly, it now doesn't work and throws the error:
The type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin`1[System.Int32]' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject.`
Searching around, some people have run into this when they have changed their table names, but I have not done this, and regardless, overriding OnModelCreating and explicitly mapping everything I can (table name, keys, column names and properties) has no effect and it still complains it isn't mapped. Plus, looking at the source code of the base classes on GitHub, the mapping should be fine anyways.
Any ideas?
It seems that in Entity Framework, you cannot map multiple levels of generic types, as EF cannot create a proxy from this. Props to this answer: Are generic classes not supported as models in Entity Framework?
If you consider IdentityDbContext.cs in the source code, this line:
public virtual IDbSet<TRole> Roles { get; set; }
is really:
public virtual IDbSet<IdentityRole<int, IdentityUserRole<int>> Roles { get; set; }
It needs to be able to make a proxy out of this very type as a whole, thus why using a derived base class works.
My theme has some sort of breadcrumb. The controller is always the category. To avoid repeat myself, I want to set it in the constructor of the controller for all actions like this:
class MyController:Controller{
public MyController() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
When I access ViewBag.BreadcrumbCategory in the layout-view, its null. In a Action it works:
class MyController:Controller{
public IActionResult DoSomething() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
I'm wondering that setting a ViewBag property is not possible in a constructor? It would be annoying and no good practice to have a function called on every action which do this work. In another question using the constructor was an accepted answear, but as I said this doesn't work, at least for ASP.NET Core.
There is an GitHub issue about it and it's stated that this is by design. The answer you linked is about ASP.NET MVC3, the old legacy ASP.NET stack.
ASP.NET Core is written from scratch and uses different concepts, designed for both portability (multiple platforms) as well as for performance and modern practices like built-in support for Dependency Injection.
The last one makes it impossible to set ViewBag in the constructor, because certain properties of the Constructor base class must be injected via Property Injection as you may have noticed that you don't have to pass these dependencies in your derived controllers.
This means, when the Controller's constructor is called, the properties for HttpContext, ControllerContext etc. are not set. They are only set after the constructor is called and there is a valid instance/reference to this object.
And as pointed in the GitHub issues, it won't be fixed because this is by design.
As you can see here, ViewBag has a dependency on ViewData and ViewData is populated after the controller is initialized. If you call ViewBag.Something = "something", then you it will create a new instance of the DynamicViewData class, which will be replaced by the one after the constructor gets initialized.
As #SLaks pointed out, you can use an action filter which you configure per controller.
The following example assumes that you always derive your controllers from Controller base class.
public class BreadCrumbAttribute : IActionFilter
{
private readonly string _name;
public BreadCrumbAttribute(string name)
{
_name = name;
}
public void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
var controller = context.Controller as Controller;
if (controller != null)
{
controller.ViewBag.BreadcrumbCategory = _name;
}
}
}
Now you should be able to decorate your controller with it.
[BreadCrumb("MyCategory")]
class MyController:Controller
{
}
I have the same issue and solve it overriding the OnActionExecuted method of the controller:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
ViewBag.Module = "Production";
}
Here is a better way to do this for .NET Core 3.x, use the ResultFilterAttribute:
Create your own custom filter attribute that inherits from ResultFilterAttribute as shown below:
public class PopulateViewBagAttribute : ResultFilterAttribute
{
public PopulateViewBagAttribute()
{
}
public override void OnResultExecuting(ResultExecutingContext context)
{
// context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
(context.Controller as MyController).SetViewBagItems();
base.OnResultExecuting(context);
}
}
You'll need to implement the method SetViewBagItems to populate your ViewBag
public void SetViewBagItems()
{
ViewBag.Orders = Orders;
}
Then Decorate your Controller class with the new attribute:
[PopulateViewBag]
public class ShippingManifestController : Controller
That's all there is to it! If you are populating ViewBags all over the place from your constructor, then you may consider creating a controller base class with the abstract method SetViewBagItems. Then you only need one ResultFilterAttribute class to do all the work.
We have the following situation: an entity and a pojo in Objectify v5.
As you can see, the entityclass has a reference to the pojo, like this:
#Entity
public class TestCustomer {
#Id
public Long id;
TestIbj ibj;
}
class TestIbj {
TestCustomer customer;
}
This fails with a StackOverflowError when we try to save it like this:
TestCustomer testCustomer = new TestCustomer();
OfyService.ofy().save().entity(testCustomer).now();
Error:
java.lang.StackOverflowError
at java.lang.Class.getMethod0(Class.java:2772)
at java.lang.Class.isCheckMemberAccessOverridden(Class.java:2214)
at java.lang.Class.checkMemberAccess(Class.java:2233)
at java.lang.Class.getDeclaredMethods(Class.java:1854)
at...
Our question is: Why is this not allowed/failing? If we change the pojo into an Entity, it works fine, but we don't understand why that is..
Thank you very much!
StackoverflowError almost always means that there is an unbounded recursion. It's the case in your code as well:
#Entity
public class TestCustomer {
#Id
public Long id;
TestIbj ibj; // TestCustomer contains TestIbj
}
class TestIbj {
TestCustomer customer; // TestIbj contains TestCustomer (which further contains TestIbj.. and so on)
}
Due to this circular dependency (shown in code above), objectify will never be able to construct object graph.
I have a stateful session bean where a list is maintained:
#Stateful
public class CartDAO{
private List<ShoppingCart> tempCart;
public void add(ShoppingCart shoppingCart){
tempCart.add(shoppingCart);
}
public List<ShoppingCart> getCart(){
return tempCart;
}
#PostConstruct
public void init(){
tempCart = new ArrayList<>();
}
}
Controller1 to add to the cart:
#Named
#SessionScoped
public class Controller1 implements Serializable {
#EJB
CartDAO cartDao;
public String addToShoppingCart() {
cartDao.add(shoppingCart);
}
}
Now, i want to ask you could i get the added items to the list from another cart?
#Named
#SessionScoped
public class Controller2 implements Serializable {
#EJB
CartDAO cartDao;
public String getShoppingCart() {
System.out.println(cartDao.getCart());//returns null
}
}
Obviously the above code returns null.
How do I retrieve the list from another controller. Any help will be much appreciated.
I don't see any obvious mistake here (are you sure that you don't call Controller2#getShoppingCart() before adding any items do your CartDAO?) but here are couple of my notions
you should have your CartDAO implement some interface or make it #LocalBean
all stateful beans should have method annotated with #Remove so you can clean the resources used in the bean (close datasources and son) and bean will be removed from the memory after this call
now it's recommended to use #Inject everywhere instead of #EJB, it's the same (you have to use #EJB only when you inject remote beans)
And also one point, if the System.out.println(cartDao.getCart()); returns null than it means the #PostConstruct haven't been called which is strange. Can you provide some more info about container and your environment?Also show us imports, this is big source of mistakes.
Is there a way to override an abstract class's method signature which uses <T> with a ClassName so I can pass an object by reference without recasting it?
For example, I have a bunch of Object Managers. I want them all to contain a .Save(Object) method which will perform the appropriate save action based on the object state (Insert, Update, Delete, etc).
I was trying to create a base class which contains these methods:
protected virtual bool Update<T>(ref T _object) where T : ObjectBase
{
throw new NotImplementedException();
}
public virtual bool Save<T>(ref T _object) where T : ObjectBase
{
// Figure out which action to take based on _object's state and execute it
}
And I wanted my inherited classes to define the methods using something like this:
public override bool Update<Consumer>(ref Consumer _object)
{
return _service.UpdateConsumer(ref _object);
}
My problem is that I can't specify that <T> will now be <Consumer>, and by keeping it at <T> I can't pass it by ref
Instead of making the methods themselves generic, you should make the entire base class generic.
For example:
public abstract class ObjectManager<T> where T : ObjectBase {
protected abstract bool Update(T obj);
}
Each concrete ObjectManager should inherit ObjectManager of the type that it manages, like this:
public class ConsumerManager : ObjectManager<Consumer> {
protected override bool Update(Consumer obj) {
...
}
}
Note, by the way, that your parameters should almost definitely not be passed ref.
You only need to ref keyword if you want to change the caller's variable to refer to a different instance.
For more information, see here.