How spring data JPA mapped split a table?
Already, I have an Entity class:
#Entity
#Table(name = "tbl_attendance_teacher_result")
#Data
public class AttendanceRecord extends TimeEntity {
#EmbeddedId
private AttendanceRecordPrimaryKey id;
private int gid;
private String teacherName;
}
but now I want to split the table tbl_attendance_teacher_result by gid;
table name like
tbl_attendance_teacher_result_1,
tbl_attendance_teacher_result_2 ...etc.
How should I modify the entity class?
Related
I have the following JsonViews defined:
public class EntityJsonView {
public static class Detailed extends Abbreviated {
}
public static class AuditedDetailed extends Detailed {
}
public static class Abbreviated {
}
}
Then I have these classes:
public Class Customer {
#JsonView(EntityJsonView.Abbreviated.class)
private Integer id;
#JsonView(EntityJsonView.Abbreviated.class)
private String name;
#JsonView(EntityJsonView.Detailed.class)
private String phone;
#JsonView(EntityJsonView.Detailed.class)
private List<Invoice> invoices;
}
public Class Invoice {
#JsonView(EntityJsonView.Abbreviated.class)
private Integer id;
#JsonView(EntityJsonView.Detailed.class)
private Customer customer;
#JsonView(EntityJsonView.Detailed.class)
private Employee salesman;
#JsonView(EntityJsonView.Abbreviated.class)
private Date invoiceDate;
#JsonView(EntityJsonView.Abbreviated.class)
private Double amount;
}
I return my customer list like this:
#JsonView(EntityJsonView.Detailed.class)
public ResponseEntity<List<Customer>> getCustomerList() {
List<Customer> custs = customerService.getAll();
return new ResponseEntity<List<Customer>>(custs , HttpStatus.OK);
}
While I want the Customer instances to be serialized using the Detailed view, I want the nested Invoice instances to be serialized using the Abbreviated view. By the same token, when I serialize a list of Invoices using the Detailed view, I want the nested Customer instances to be serialized using the Abbreviated view. This is not just a problem of recursion because there are lots of other attributes I want to remove as well.
I've searched high and low for a solution but perhaps I'm not using the right keywords.
My predecessor in this job accomplished this using #JsonIgnoreProperties but that is proving to be a maintenance problem. When a new attribute is added to a class, I have to hunt down all the ignore lists and decide if it needs to be ignored or not. It would be easier if there was a corresponding #JsonIncludeProperties.
Has anyone found a better way to accomplish this?
I figured out a way to sort of do this and it works for my environment. I'm posting in case someone else has a similar issue. The first step is to create a view for each of your top-level entities. In this example, those will be Foo, Bar, and Snafu. These should all inherit from an abbreviated view.
public class EntityViews {
public static interface Abbr {}
public static interface Foo extends Abbr {}
public static interface Bar extends Abbr {}
public static interface Snafu extends Abbr {}
public static interface Detailed extends Foo, Bar, Snafu {}
}
I used interface because it allows multiple inheritance. All the main class views end up in the Detailed view. Now for the classes:
#JsonView(EntityViews.Foo.class)
public class Foo {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
private String description;
private Bar bar;
}
#JsonView(EntityViews.Bar.class)
public class Bar {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
private List<Snafu> snafus;
}
#JsonView(EntityViews.Snafu.class)
public class Snafu {
#JsonView(EntityViews.Abbr.Class)
private Integer id;
#JsonView(EntityViews.Abbr.Class)
private String name;
#JsonView(EntityViews.Bar.class, EntityViews.Snafu.class)
#JsonIgnoreProperties("parent", "children")
private Snafu parent;
#JsonIgnoreProperties("parent", "children")
private List<Snafu> children;
}
Now, let's do the endpoints:
#RestController
#RequestMapping("/api/foos")
#CrossOrigin
public class FooController {
#JsonView(EntityViews.Foo.class)
#GetMapping("/")
public ResponseEntity<List<Foo>> get() {
List<Foo> list = service.getAll();
return new ResponseEntity<List<Foo>>(list, HttpStatus.OK);
}
}
#RestController
#RequestMapping("/api/bars")
#CrossOrigin
public class BarController {
#JsonView(EntityViews.Bar.class)
#GetMapping("/")
public ResponseEntity<List<Foo>> get() {
List<Bar> list = service.getAll();
return new ResponseEntity<List<Bar>>(list, HttpStatus.OK);
}
}
#RestController
#RequestMapping("/api/snafus")
#CrossOrigin
public class SnafuController {
#JsonView(EntityViews.Snafu.class)
#GetMapping("/")
public ResponseEntity<List<Snafu>> get() {
List<Snafu> list = service.getAll();
return new ResponseEntity<List<Snafu>>(list, HttpStatus.OK);
}
}
So as we see, each controller assigns the view corresponding to the entity that is being returned. Since those views all
inherit from Abbr, all other entities being returned will have the Abbr view applied to them.
Notice in the Snafu class that the parent attribute is assigned to both the Bar and Snafu views. So when you return a Bar endpoint,
you will get that attribute as well as the Abbr attributes (I haven't tested this so YMMV. Will edit if it doesn't work like I think it will).
The one place this strategy breaks down is if you have attributes that are the same class as the entity. In that case, you will still
have to use #JsonIgnoreProperties to control what is returned but that is a small price to pay for not having to have those on virtually
every entity attribute.
I have the following scenario:
public class Stay
{
[Contained]
public Guest PrimaryGuest {get;set;}
}
public abstract class Guest
{
public int ID {get; set;}
}
public class EntityGuest : Guest
{
public string EntityName {get;set;}
}
public class PersonGuest : Guest
{
public string SurName {get;set;}
public string GivenName {get;set;}
}
When querying for the stays, I wish to order by a PersonGuest/SurName.
I know how to order by a child property: [URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ID - but how would I order by on a child property that is derived? Is it even possible? I could not determine it by the OData documentation - it wasn't at least called out for contained entities.
This answer helped me a lot in a similar scenario: oData $expand on Derived Types
Basically you can 'Cast' any complex or entity typed property in your query by adding a forward slash and the qualified name of the model type, using the namespace you have defined for your model, not the .Net full type name.
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ModelNamespace.PersonGuest/Surname
If you are unsure of the model namespace, look at the model builder code, or use something similar to this:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "MyAppModel";
Then your URL should look like this:
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/MyAppModel.PersonGuest/Surname
I need to have two domains which are extends from one domain. However when i create the domains subdomains' tables are not created.
class BaseEntity {
Date created
Boolean isDeleted
Date modified
Integer version
static mapping = {
tablePerHierarchy false
version false
table name: "base_entity", schema: "user"
isDeleted defaultValue: Boolean.FALSE
}
}
First domain extends from BaseEntity
class UserEx extends BaseEntity {
String firstName
String lastName
String password
String userName
static mapping = {
version false
table name: "user_ex", schema: "user"
}
}
This is the second domain
class UserType extends BaseEntity {
Integer name
static belongsTo = [parent: UserType]
static hasMany = [child:UserType]
static mapping = {
version false
table name: "user_type", schema: "user"
}
}
In the db the only created table is BaseEntity. If i remove tablePerHierarchy property from BaseEntity domain, created table(which is BaseEntity) contains all fields of userEx and userType - this is not we like to have-
To sum up I want to have those three tables in my db without losing extends relationship.
Thanks in advance
I have two domain classes (db tables) in my Grails project:
class Doctor {
String role;
String name;
String surname;
String address;
...
#NotNull
static belongsTo = [secUser:SecUser]
....
}
class SecUser {
transient springSecurityService
String username
String password
...
}
I would like to find all SecUser that have not a correspondent Doctor.
How can I do it?
I think you need something like this:
SecUser.executeQuery(" FROM SecUser secUser WHERE NOT EXISTS (SELECT doctor.SecUser FROM Doctor doctor")
As I understand a connection string is attached to one class only. But what if I have many Model classes? Can I use one connection string for multiple classes?
This is a simple version of my UserModel.cs file:
public class UserModel
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserTable : DbContext
{
public UserModel GetByEmail(string Email)
{
return this.Database.SqlQuery<UserModel>("SELECT * FROM Users WHERE Email=#Email", new SqlParameter("Email", Email)).SingleOrDefault();
}
}
And this is the connection string:
<connectionStrings>
<add name="UserModel"
connectionString="Server=.\SQLEXPRESS;Database=MyDatabase;User Id=MyUser;Password=MyPassword;"
providerName="System.Data.SqlClient" />
</connectionStrings>
Now lets say I want to add a new Model class named DataTable also derived from DbContext as user table is. Do I need a connection string named the same or can I use the already defined one? What is the conventional way of dealing with multiple Model classes and connection strings?
The DbContext class uses the ConnectionString to make the connection to the database.
You normally have multiple model classes exposed by a DbContext.
It is possible to have multiple DbContext objects that use the same connection string value to connect to the database. In this way, you can separate portions of your model into separate contexts if desired (for example, if you are creating separate assemblies that access different tables but provide similar services to the application).
One caveat to note with EF up to at least 5.0, you cannot use the code-first migrations with multiple DbContexts, one will overwrite the other's changes. The solution to this is to create an aggregated DbContext that is only used for the Migrations process.
I've done this in an app that I built. I used the Unity IoC container, and the built a Plugin Interface that allowed me to pass my ConnectionStringName into my separated DbContexts. An example of the plugin in one of the assemblies was:
public class Bootstrapper : IBootstrapper
{
public void Bootstrap(IUnityContainer container, string connectionStringName)
{
container.RegisterType<ISQService, SQService>();
container.RegisterType<ISQEntities, SQEntities>(
new HierarchicalLifetimeManager(), new InjectionConstructor(connectionStringName));
container.RegisterType<IController, SQController>("SQ");
}
}
My global.asax referenced the bootstrapper class below:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders[typeof(DataTable)] = new DataTableModelBinder();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Bootstrapper.Initialise();
}
protected void Application_End()
{
Bootstrapper.Dispose();
}
Bootstrapper
public static class Bootstrapper
{
private static IUnityContainer container;
public static void Initialise()
{
container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
public static void Dispose()
{
container.Dispose();
}
private static void RegisterPlugins(IUnityContainer theContainer, string wildcard, string connectionStringName)
{
var pluginBootStrappers = from Assembly assembly in wildcard.LoadAssemblies()
from type in assembly.GetExportedTypes()
where typeof(IBootstrapper).IsAssignableFrom(type)
select (IBootstrapper)Activator.CreateInstance(type);
pluginBootStrappers.ToList().ForEach(b => b.Bootstrap(theContainer, connectionStringName));
}
private static IUnityContainer BuildUnityContainer()
{
var theContainer = new UnityContainer();
const string ConnectionStringName = "MyDb";
RegisterPlugins(theContainer, "MyApp.Systems.*.dll", ConnectionStringName);
// Register Application Specific objects
theContainer.RegisterType<IMyEntities, MyEntities>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(ConnectionStringName));
theContainer.RegisterType<IAimaService, AimaService>();
var factory = new UnityControllerFactory(theContainer);
ControllerBuilder.Current.SetControllerFactory(factory);
return theContainer;
}
}
The connection string defines the parameters needed to connect to the DB.
Maybe I think you are talking about or confusing the SQL Query with the connectionstring.
Yes one SQL Query can QUERY more than one table at any given time.
Maybe you could look into the "SQL Query Statement" on google for in depth information.