2016-12-01 2 views
1

Ich habe eine übergeordnete und eine untergeordnete Komponente. Ich möchte den Elternteil gleichzeitig mit dem Kind erstellen, da der Elternteil ohne das Kind nicht existieren kann. Speziell habe ich eine subscriptions, die has_manyservicesErstellen Eltern, Kind verschachtelte Assoziation mit erforderlichen Foreign_id gleichzeitig in Ecto

Wenn mein Kind-Modell ein erforderliches Feld ist die Fremdeinschränkung, wie erstelle ich beide Modelle zur gleichen Zeit? Ich erhalte einen Fehler in meinem Changeset, der anzeigt, dass die parent.id nicht leer sein kann.

Ich weiß, ich kann Repo.insert!(Subscription) tun, gefolgt von der Erstellung eines Service Changeset mit subscription.id, aber ich frage mich, ob es möglich ist, beide zur gleichen Zeit zu erstellen?

Parent (Abonnement)

def changeset(struct, params \\ %{}) do 
# get the current time and add 30 days. 
    {:ok, active_until} = DateTime.utc_now() 
     |> DateTime.to_unix() |> Kernel.+(2592000) |> DateTime.from_unix() 

    struct 
    |> change(active_until: active_until) 
    |> cast(params, [:active_until, :user_id]) 
    |> cast_assoc(:services) 
    |> validate_required([:active_until]) 
end 

Child (Service)

def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:start_time, :frequency, :subscription_id]) 
    |> validate_required([:subscription_id]) 
    |> foreign_key_constraint(:subscription_id) 
end 
+0

Welches Feld im Abonnement hängt von Dienst tut hier Dies sollte? Und können Sie die genaue Fehlermeldung posten? – Dogbert

Antwort

1

Dies ist ein Ei-Huhn Problem:

Meine Eltern und Kind Changesets sind unten aufgeführt die eindeutige ID wird vom Datenbankmodul dem Stammsatz zugewiesen. Es ist also unmöglich, dies in einer einzigen Transaktion auszuführen.

Die einzige Möglichkeit, die ID Taste auf Master-Tabelle, dich über DB interne Funktion zu handhaben wäre GUID zu erzeugen (wie UUID() in MySQL oder CREATE SEQUENCE in PostgreSQL.) In diesem Fall könnte man diese Funktion im Voraus anrufen und setze die ID explizit.

Ich würde den letzteren Ansatz jedoch nicht empfehlen.

0

Dies ist eine alte Frage, aber beantworten, falls jemand anders hier landet wie ich.

def changeset(%Subscription{} = subscription, attrs) do 
    subscription 
    |> cast(attrs, [...]) 
    |> ... 
    |> cast_assoc(:services, required: true) 
    |> ... 
end 

def create_subscription(attrs \\ %{}) do 
    %Subscription{} 
    |> Subscription.changeset(attrs) 
    |> Repo.insert() 
end 

den Job