Creating self relation in prisma - prisma

I want to add a self relation on my user table but it seems there is an issue with the way am doing it.
model User {
id BigInt #id(map: "user_pkey") #unique(map: "user_id_key") #default(autoincrement())
firstname String? #db.VarChar
lastname String? #db.VarChar
username String? #unique #db.VarChar
email String? #db.VarChar
password String? #db.VarChar
organization String? #db.VarChar
createdAt DateTime? #db.Timestamptz(6)
updatedAt DateTime? #db.Timestamptz(6)
parent_id BigInt?
deletedAt DateTime? #db.Timestamptz(6)
deleted_by BigInt?
##map("users")
parent User? #relation(fields: [parent_id], references: [id]) // this line gives me error
}
I see the following error :
```Error validating field parent in model User: The relation field parent on model User is missing an opposite relation field on the model User. Either run prisma format or add it manually.
What am i doing wrong here?

Can you try this schema?
model User {
id BigInt #id(map: "user_pkey") #unique(map: "user_id_key") #default(autoincrement())
firstname String? #db.VarChar
lastname String? #db.VarChar
username String? #unique #db.VarChar
email String? #db.VarChar
password String? #db.VarChar
organization String? #db.VarChar
createdAt DateTime? #db.Timestamptz(6)
updatedAt DateTime? #db.Timestamptz(6)
parent_id BigInt?
deletedAt DateTime? #db.Timestamptz(6)
deleted_by BigInt?
parent User? #relation("UserParent", fields: [parent_id], references: [id]) // this line gives me error
usersAsParents User[] #relation("UserParent")
##map("users")
}
For reference, here is a guide on Self-Relations.

Related

Prisma.js mongodb relation filter doesn't work

I have a model Post that looks like this:
model Post {
id String #id #default(auto()) #map("_id") #db.ObjectId
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
...
...
...
LikedPosts LikedPost[]
}
and model LikedPost that looks like this:
model LikedPost {
id String #id #default(auto()) #map("_id") #db.ObjectId
createdAt DateTime #default(now())
post Post #relation(fields: [postId], references: [id])
postId String
user User #relation(fields: [userId], references: [id])
userId String
##unique([userId, postId])
}
I'm trying to return all posts that user liked inside db.post.findMany with this prisma filter:
where: {
LikedPosts: {
some: {
userId: {
equals: session.userId as string,
},
},
},
},
But it always returns empty array as a result.
Even if I put raw value instead of session.userId like "62d6b8d220ba0fa6d5cea60f" of the user that has liked posts, it still returns nothing.
It doesn't even work inside Prisma Studio.
Am I doing something wrong here?
The answer was to add #db.ObjectId to the userId field in prisma Schema like this:
model LikedPost {
id String #id #default(auto()) #map("_id") #db.ObjectId
createdAt DateTime #default(now())
post Post #relation(fields: [postId], references: [id])
postId String #db.ObjectId
user User #relation(fields: [userId], references: [id])
userId String #db.ObjectId
##unique([userId, postId])
}

How to model a tournament in Prisma

I want to model a tournament in Prisma. I have this:
model Tournament {
id Int #id #default(autoincrement())
meets Meet[]
}
model Meet {
id Int #id #default(autoincrement())
name String
matches Match[]
}
model Match {
id Int #id #default(autoincrement())
player1Id Int
player2Id Int
meet Meet #relation(fields: [meetId], references: [id])
meetId Int
}
model Player {
id Int #id #default(autoincrement())
name String
}
model Result {
id Int #id #default(autoincrement())
matchId Int
playerId Int
}
I feel the Match model might need to link player1 and player2 (with a relation) to the Player model. I'm also not sure how the result should be modelled.
Any advice will be appreciated.
You can do it as follow:
datasource mysql {
provider = "mysql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
generator erd {
provider = "prisma-erd-generator"
output = "./entity-relationship-diagram.svg"
}
model Tournament {
id Int #id #default(autoincrement())
name String
meets Meet[] #relation()
}
model Meet {
id Int #id #default(autoincrement())
name String
tournament Tournament #relation(fields: [tournamentId], references: [id])
tournamentId Int
matches Match[] #relation()
}
model Match {
id Int #id #default(autoincrement())
name String
meeet Meet #relation(fields: [meetId], references: [id])
meetId Int
players Player[] #relation("matchPlayers", fields: [playerId], references: [id])
playerId Int
winner Player? #relation("matchWinner", fields: [winnerId], references: [id])
winnerId Int?
score Score[] #relation()
}
model Player {
id Int #id #default(autoincrement())
name String
matchesPlayers Match[] #relation("matchPlayers")
matchesWinner Match[] #relation("matchWinner")
score Score[] #relation()
}
model Score {
id Int #id #default(autoincrement())
score Int
match Match #relation(fields: [matchId], references: [id])
matchId Int
player Player #relation(fields: [playerId], references: [id])
playerId Int
}
And it will generate the following database

Elastic scale query with EF: Nullable object must have a value

On Azure, I have a setup of several sharded databases and an elastic query database with external tables mirroring the tables on the shards. The two main tables I use are:
Channels:
[Name] nvarchar NOT NULL,
[Id] [uniqueidentifier] NOT NULL,
[ExternalReference] nvarchar NULL
Users:
[Email] nvarchar NOT NULL,
[FirstName] nvarchar NOT NULL,
[LastName] nvarchar NOT NULL,
[ChannelId] [uniqueidentifier] NOT NULL,
[Status] [int] NOT NULL,
[AvatarId] [uniqueidentifier] NULL,
[Id] [uniqueidentifier] NOT NULL
When I query this via EF and linq:
var user = db.Users.Include("Channel").FirstOrDefault(u => u.Email ==
"tony#soprano.com");
I get an error:
An error occurred while executing GlobalQuery operation: Nullable object must have a value.
This is what the User class looks like:
public class User
{
public Guid Id { get; set; } = SequentialGuid.NewGuid();
[Required]
public string Email { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Index]
public Status Status { get; set; }
public Guid? AvatarId { get; set; }
[Index]
public Guid ChannelId { get; set; }
[ForeignKey("ChannelId")]
public virtual Channel Channel { get; set; }
}
Querying directly via T-SQL:
SELECT * FROM Users INNER JOIN Channels ON Users.ChannelId = Channels.Id
gives me the same error.
Further investigation shows that casting the Ids to uniqueidentifiers (which they already are) solves the problem:
SELECT * FROM Users INNER JOIN Channels ON CAST(Users.ChannelId as uniqueidentifier) = CAST(Channels.Id as uniqueidentifier)
The ChannelId and Id Columns are already non nullable uniqueidentifiers. The data inside the shards is also valid and not null, so what exactly is the problem here?
Another question: how can I force that ‘cast to uniqueidentifier’ in linq?
Quick question, you state that "Querying directly via T-SQL:
SELECT * FROM Users INNER JOIN Channels ON Users.ChannelId = Channels.Id
gives me the same error." , are you querying from the Elastic Query Head database, or on a shard? I setup the schema and could not repro when querying from the shard, so I am wondering if I am not repro'ing the issue correctly?

EF Code First Multiple Tables to single entity

I'm just starting out with Entity Framework and I seem to be misunderstanding something. Basically I've got a database already setup. Let's say the following are my tables.
**Employees**
EmployeeId
CubeId (FK to Cubes table)
NameId (FK to Name table)
**Cubes**
CubeId
CubeName
**Person**
NameId
FirstName
LastName
I want to be able to write something like this: SELECT EmployeeId, CubeId, CubeName, FirstName, LastName FROM Employees LEFT OUTER JOIN Cubes LEFT OUTER JOIN Person. So it would return all of the Employees. Basically, in EF Code First do you have to create a class for EVERY table? If not, how do you create a LEFT OUTER Join equivalent? All of the examples I've found use navigational properties to go from table to table (i.e. class to class).
Models:
public class Employee
{
[Key]
public int EmployeeId {get;set;}
public int CubeId {get;set;}
[ForeignKey("Cube")]
public int NameId {get;set;}
[ForeignKey("Name")]
public virtual Cube Cube {get;set;}
public virtual Name Name {get;set;}
}
public class Cube
{
[Key]
public int CubeId {get;set;}
public string CubeName {get;set;}
}
public class Name
{
[Key]
public int NameId {get;set}
public string FirstName {get;set;}
public string LastName {get;set;}
}
Your context:
public class YourContext:DbContext
{
public DbSet<Name> Names {get;set;}
public DbSet<Cube> Cubes {get;set;}
public DbSet<Employee> Employees {get;set;}
}
Your query:
YourContext db = new YourContext();
var query = db.Employees.Where(x => x.EmployeeId == id).Select(x => new
{
EmployeeId = x.EmployeeId,
CubeId = x.Cube.CubeId,
CubeName = x.Cube.CubeName,
FirstName = x.Name.FirstName,
LastName = x.Name.LastName
}).FirstOrDefault();
This will locate first employee that has some id (or return null if there's none), and then create a type that has all the properties you mentioned. If you need last name, you access it with:
string lastName = query.LastName;

Autogenerate primary key (Guid) Entity Framework CTP5

I have a following POCO class
public class Account
{
[Key,DatabaseGenerated(DatabaseGenerationOption.Identity)]
public string AccountId { set; get; }
public string FirstName { set; get; }
public string LastName { set; get; }
public string Email { set; get; }
}
I get the following exception when the database gets created
Identity column 'AccountId' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, and constrained to be nonnullable.
Shouldn't you have:
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid AccountId { set; get; }
?
Jeff's answer is right. Just a little tip for you. Using EF6 I wrote next configuration in order to set all fields with name "Id" and type "Guid" as identity.
modelBuilder.Properties<Guid>()
.Where(info => info.Name.ToLower()== "id")
.Configure(configuration => configuration.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity));
So I don't have to write [DatabaseGenerated(DatabaseGenerationOption.Identity)] everytime.
Sound like you have to update your AccountId property from string to one of the mentioned datatypes in the exception:
int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, and constrained to be nonnullable
Any reason why it's now a string?